Direct path read and fast full index scans
This is yet another blogpost on Oracle’s direct path read feature which was introduced for non-parallel query processes in Oracle version 11.
For full table scans, a direct path read is done (according to my tests and current knowledge) when:
– The segment is bigger than 5 * _small_table_threshold.
– Less than 50% of the blocks of the table is already in the buffercache.
– Less than 25% of the blocks in the buffercache are dirty.
Also (thanks to Freek d’Hooge who pointed me to an article from Tanel Poder) you can change the optimizer statistics to change the segment size for the direct path decision. Please mind that whilst this uses the statistics the optimizer uses, this is NOT an optimizer decision, but a decision made in the “code path”, so during execution.
So let’s take a look at my lab environment (Oracle Linux 6.3, 64 bit, Oracle 11.2.0.3 and ASM)
Small table threshold:
NAME VALUE -------------------------------------------------- ------- _small_table_threshold 1011
Table information:
TS@v11203 > select blocks from user_segments where segment_name = 'T2'; BLOCKS ---------- 21504
So if we take small table threshold times and multiply it by five, we get 5055. This means that the size of table T2 is more than enough so should be scanned via direct path:
TS@v11203 > select s.name, m.value from v$statname s, v$mystat m where m.statistic#=s.statistic# and s.name = 'table scans (direct read)'; NAME VALUE ---------------------------------------------------------------- ---------- table scans (direct read) 0 TS@v11203 > select count(*) from t2; COUNT(*) ---------- 1000000 TS@v11203 > select s.name, m.value from v$statname s, v$mystat m where m.statistic#=s.statistic# and s.name = 'table scans (direct read)'; NAME VALUE ---------------------------------------------------------------- ---------- table scans (direct read) 1
Well, that’s that, this seems quite simple.
I’ve created a relatively big table and created a (normal) index on it in the same database. The index is created on a single column, called ‘id’. If I issue a count(id), the whole index needs to be scanned, and Oracle will choose a fast full index scan. A fast full index scan is a scan which just needs to read all the blocks, not necessarily in leaf order. This means it can use multiblock reads (which reads in the order of allocated adjacent blocks).
Let’s check just to be sure:
TS@v11203 > select count(id) from bigtable; Execution Plan ---------------------------------------------------------- Plan hash value: 106863591 ------------------------------------------------------------------------------------ | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | 13 | 19662 (2)| 00:03:56 | | 1 | SORT AGGREGATE | | 1 | 13 | | | | 2 | INDEX FAST FULL SCAN| I_BIGTABLE | 34M| 425M| 19662 (2)| 00:03:56 | ------------------------------------------------------------------------------------ Note ----- - dynamic sampling used for this statement (level=2)
If we look at the index size, the size of the index makes this segment a candidate for direct path reads:
TS@v11203 > select blocks from user_segments where segment_name = 'I_BIGTABLE'; BLOCKS ---------- 72704
If we look at number of small table threshold times five (5055), this index is much bigger than that. Also, this is bigger than table T2. Let’s execute select count(id) from bigtable, and look at the statistic ‘index fast full scans (direct read)’:
TS@v11203 > select s.name, m.value from v$statname s, v$mystat m where m.statistic#=s.statistic# and s.name = 'index fast full scans (direct read)'; NAME VALUE ---------------------------------------------------------------- ---------- index fast full scans (direct read) 0 TS@v11203 > select count(id) from bigtable; COUNT(ID) ---------- 32000000 TS@v11203 > select s.name, m.value from v$statname s, v$mystat m where m.statistic#=s.statistic# and s.name = 'index fast full scans (direct read)'; NAME VALUE ---------------------------------------------------------------- ---------- index fast full scans (direct read) 0
Huh? This statistic tells me there hasn’t been a direct path read! This means that this read has been done in the “traditional way”. This is a bit…counter intuitive. I’ve traced the session, and indeed it’s doing the traditional multiblock reads via the scattered read waits.
I did a fair bit of fiddling around with the parameters which are reported to be involved, and found out I can get the database to do direct path reads by changing the parameter “_very_large_object_threshold”. The information found on the internet reports this value is in megabytes. A quick stroll through a number of different database (all on 11.2.0.3) shows this parameter is quite probably statically set at “500”.
If I calculate the size in megabytes of the index I_BIGTABLE, the size is 568M. This is clearly higher than the value of “_very_large_object_threshold”. I can get the same index scanned via direct path reads by changing the value of “_very_large_object_threshold” to 100.
This interesting, because it looks like this parameter does the same for full scans on index segments as “_small_table_threshold” does for full scans on table segments: the size of the segment to be scanned needs to be bigger than five times.
There are also differences: small table threshold is set in blocks, (apparently) very large object threshold is set in megabytes. Also, small table threshold is set by default at 2% of the size of the buffercache (so it scales up with bigger caches), very large object threshold seems to be fixed at 500. If my finding is correct, then it means an index segment needs to be bigger than 500*5=2500M to be considered for direct path reads. It’s unknown to me if the 50% limit for blocks in the cache and the 25% limit for dirty blocks is subject to this too.
As I know, “_very_large_object_threshold” is as percentage, I’m also tested it, but with changing index/table stats through sql profile: http://orasql.org/2013/03/18/example-of-controlling-direct-path-reads-decision-through-sql-profile-hints/
ie, “_db_block_buffers”*”_very_large_object_threshold”/100
Pingback: Forcing Smart Scans on Exadata – is _serial_direct_read parameter safe to use in production? | Tanel Poder's blog: IT & Mobile for Geeks and Pros
an interessting article. There is a small typo: “Less than 25% of the blocks in the buffercache are directy.” – should be “dirty”, I assume.
Thanks for reading Martin!
Indeed, ‘dirty’ is meant here. I’ve corrected it in the text.
HI, I recently saw a application degrade with direct path read temp wait event. The difference was that in the plan the index access changed from index fast full scan to index full scan. The wait event to be set for disabling the direct path read feature was given as 10949 by oracle support.
Have you played around with this event ever ?
Regards
Dhairyasheel
I think I have some clearance about VLOT in here: http://progeeking.com/2014/02/25/the-big-q-direct-path-and-cell-offloading/
Pingback: Direct path and buffered reads again: compressed tables. | Frits Hoogland Weblog
Pingback: what happens when table does not fit to keep pool — orabase.org