Analyze index validate structure - the dark side
Recently, a co-worker encountered a significant performance hurdle after a database upgrade. The plan included verifying object integrity using analyze table <tablename> validate structure cascade. While most tables processed quickly, one specific table appeared to hang.
After killing the job and analyzing objects individually, they found the culprit: a single index.
The 3-Day Wait: Why Index Validation Fails
When asked how long the process had been running, the answer was shocking: three days. A 10046 trace revealed the process was consumed by db file sequential read events on the table.
The root cause? Clustering Factor.
The analyze index process verifies every row. If the table is well-ordered (clustered) according to the index, the number of blocks read will be close to the actual block count of the table. However, if the table is poorly ordered, the system may read the same blocks from disk millions of times as it "walks" the index.
Illustrating Poor Clustering
Consider rows with IDs 1 through 5.
- Good Clustering: IDs 1, 2, 3, 4, and 5 are in the same block. One read fetches all five.
- Poor Clustering: Each ID is in a different block. Five separate reads are required.
| ID | Block Number |
| 1 | 22 |
| 2 | 75 |
| 3 | 16 |
| 4 | 2 |
| 5 | 104 |
In this case 5 separate blocks must be read to retrieve these rows. In the course of walking the index, some minutes later these rows must also be read:
| ID | Block Number |
| 1048576 | 22 |
| 1048577 | 75 |
| 1048578 | 16 |
| 1048579 | 2 |
| 1048580 | 104 |
Later, when the index reaches IDs 1048576 through 1048580, it may need those same blocks again. By then, they've likely been aged out of the cache, forcing yet another physical disk read.
Testing the Theory: 10 Million Rows
To see how bad this can get, we ran a test with $10^7$ (10 million) rows.
-- 1e3 x 1e4 = 1e7 rows def level_1=1e3 def level_2=1e4 create table validate_me pctfree 0 as select -- floor(dbms_random.value(1,1e6)) id, -- For bad clustering factor rownum id, -- For good clustering factor substr('ABCDEFGHIJKLMNOPQRSTUVWXYZ',mod(rownum,10),15) search_data, rpad('x',100,'x') padded_data from (select null from dual connect by level <= &level_1) a, (select null from dual connect by level <= &level_2) b; create index validate_me_idx1 on validate_me(id, search_data);
Measuring the Impact
Using a custom script to check the clustering factor, we see that for a poorly ordered table, the factor is nearly equal to the number of rows:
TABLE NAME TABLE ROWS INDEX NAME LEAF BLOCKS CLUSTERING FACTOR ----------- ----------- --------------- ----------- ----------------- VALIDATE_ME 10,000,000 VALIDATE_ME_IDX1 45,346 10,160,089
The validation results were stark:
- Poorly Ordered Table: 46 minutes and 6 seconds.
- Well-Ordered Table: 1 minute and 40 seconds.
Analyzing the Trace File
By analyzing the 10046 trace, we can see exactly how many times each block was visited.
Well-Ordered Results
Using command-line tools like awk, sort, and uniq, we verified that in a well-ordered table, no block was read more than once
$> tail -n +64 trace.trc | grep "db file sequential read" | awk '{ print $10 }' | sort | uniq -c | sort -n | tail 1 743000 1 743001 1 743002
Poorly-Ordered Results
In contrast, for the poorly ordered table, the most active blocks were read 53 to 55 times each
$> tail -n +51 trace.trc | grep "db file sequential read" | awk '{ print $10 }' | sort | uniq -c | sort -n | tail -5 54 635330 55 523616 55 530064 55 626066 55 680250
Smarter Alternatives to Manual Validation
If your goal is to find block corruption or ensure integrity, analyze index validate structure may be the most expensive way to do it.
1. Use RMAN
RMAN can check for physical and logical corruption across the entire database without the overhead of walking every index entry
RMAN> backup check logical validate database;
In our test, RMAN validated the entire database in just 25 minutes—significantly faster than the 46 minutes spent on a single large index.
2. Rebuild the Index
If you suspect an index is corrupt, it is often more efficient to simply rebuild it. On Enterprise Edition, this can be done online
SQL> alter index validate_me_idx1 rebuild online; -- Elapsed: 00:00:59.88
Creating the index took 28 seconds and the rebuild took 60 seconds. Both are vastly superior to waiting 40 minutes (or three days) for validation.
The conclusion is clear: use analyze index validate structure with extreme caution on large indexes. The resource intensity and time required often outweigh the benefits when faster alternatives like RMAN or index rebuilds exist.
Oracle Database Consulting Services
Ready to optimize your Oracle Database for the future?
Share this
Share this
More resources
Learn more about Pythian by reading the following blogs and articles.
How to fix dbupgrade script issue when upgrading Oracle Database Standard Edition
Oracle E-Business Suite Database Upgrade to 19c
HOWTO: Oracle Cross-Platform Migration with Minimal Downtime
Ready to unlock value from your data?
With Pythian, you can accomplish your data transformation goals and more.