HelloDBA [中文]
Search Internet Search HelloDBA
  Oracle Technology Site. email: fuyuncat@gmail.com  MSN: fuyuncat@hotmail.com Add to circle  acoug  acoug 

Oracle 11g Direct IO Auto Tune

[中文]

Author:  fuyuncat

Source:  www.HelloDBA.com

Date:  2012-01-04 05:25:31

Share to  Twitter Facebook GMail Blogger Orkut Google Bookmarks Sina Weibo QQ Renren Tieba Kaixin Douban Taobao

Generally, Direct IO faster than Read into Cache because it does not require to allocate memory. In 11g, Oracle intruduced a new feature --- Direct IO Auto Tuning --- to improve performance of reading/writing large size objects. It will determine whether to read data blocks directly from disk bypassing buffer cache or not, basing on the size of object and size of buffer cache.

To demostrate how it works, we retrieve the principle parameters relating to this feature.

SQL代码
  1. (11.2.0.1)  
  2. HELLODBA.COM>select name, value from all_parameters where name in ('_very_large_object_threshold''_small_table_threshold''_db_block_buffers','_serial_direct_read');  
  3.   
  4. NAME                                               VALUE  
  5. -------------------------------------------------- ------------------------------  
  6. _db_block_buffers                                  10912  
  7. _small_table_threshold                             218  
  8. _very_large_object_threshold                       500  
  9. _serial_direct_read                                FALSE  

And then, create a testing table as below,

SQL代码
  1. HELLODBA.COM>create table dummy_obj as  select a.* from t_objects a, t_objects b where rownum<=18000;  
  2.   
  3. Table created.  
  4.   
  5. HELLODBA.COM>exec dbms_stats.gather_table_stats('DEMO','DUMMY_OBJ');  
  6.   
  7. PL/SQL procedure successfully completed.  
  8.   
  9. HELLODBA.COM>exec dba_seg_info('DUMMY_OBJ');  
  10. Total Blocks............................256  
  11. Total Bytes.............................2097152  
  12. Unused Blocks...........................46  
  13. Unused Bytes............................376832  
  14. Last Used Ext FileId....................5  
  15. Last Used Ext BlockId...................20608  
  16. Last Used Block.........................82  
  17. Blocks under HWM........................210  
  18.  *************************************************  
  19. The segment is analyzed  
  20. 0% -- 25% free space blocks.............0  
  21. 0% -- 25% free space bytes..............0  
  22. 25% -- 50% free space blocks............0  
  23. 25% -- 50% free space bytes.............0  
  24. 50% -- 75% free space blocks............0  
  25. 50% -- 75% free space bytes.............0  
  26. 75% -- 100% free space blocks...........0  
  27. 75% -- 100% free space bytes............0  
  28. Unused Blocks...........................0  
  29. Unused Bytes............................0  
  30. Total Blocks............................198  
  31. Total bytes.............................1622016  
  32.   
  33. PL/SQL procedure successfully completed.  
  34.   
  35. HELLODBA.COM>alter table dummy_obj move;  
  36.   
  37. Table altered.  
  38.   
  39. HELLODBA.COM>alter system flush buffer_cache;  
  40.   
  41. System altered.  

Here, we created table with 210 blocks under HWM and flushed out from buffer cache (Note: Moving table will lead the data blocks in buffer to be obsolete.). Then we perform a full table scan on it.

SQL代码
  1. D:\HelloDBA.COM\perl scripts>perl getsqlstats.pl  
  2. tnsname (default is orcl):  
  3. user name (default is demo):  
  4. password:  
  5. Array size (Default is 32):  
  6. Execution plan format (Default is TYPICAL):  
  7. SQL to be executed (without ;):  
  8. select * from dummy_obj  
  9.   
  10. Seesion ID: 16  Process ID: 4960  
  11. SQL Prepared. Process paused, press ENTER to continue...  
  12. SQL is executing ...  
  13. SQL Executed. Process Paused, press ENTER to continue...  
  14. SQL_ID  81tza277w8r6h, child number 0  
  15. -------------------------------------  
  16. select * from dummy_obj  
  17.   
  18. Plan hash value: 18537087  
  19.   
  20. -------------------------------------------------------------------------------  
  21. | Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |  
  22. -------------------------------------------------------------------------------  
  23. |   0 | SELECT STATEMENT  |           |       |       |    60 (100)|          |  
  24. |   1 |  TABLE ACCESS FULL| DUMMY_OBJ | 18000 |  1283K|    60   (2)| 00:00:01 |  
  25. -------------------------------------------------------------------------------  
  26.   
  27. statistics  
  28. -----------------------------------------  
  29. consistent changes: 0  
  30. consistent gets: 748  
  31. consistent gets direct: 0  
  32. consistent gets from cache: 748  
  33. db block changes: 2  
  34. db block gets: 1  
  35. db block gets direct: 0  
  36. db block gets from cache: 1  
  37. physical reads: 202  
  38. physical reads cache: 202  
  39. physical reads direct: 0  
  40. physical writes: 0  
  41. physical writes direct: 0  
  42. recursive calls: 20  
  43. session logical reads: 749  

The behaviors just like in 10g --- Data blocks were read from disk into buffer cache.

Now, we increase number of blocks to 219 ( just larger than _small_table_threshold), and see what will happen.

SQL代码
  1. HELLODBA.COM>insert /*+append*/into dummy_obj select a.* from t_objects a, t_objects b where rownum<=18800;  
  2.   
  3. 18800 rows created.  
  4.   
  5. HELLODBA.COM>commit;  
  6.   
  7. Commit complete.  
  8.   
  9. HELLODBA.COM>exec dba_seg_info('DUMMY_OBJ');  
  10. Total Blocks............................256  
  11. Total Bytes.............................2097152  
  12. Unused Blocks...........................37  
  13. Unused Bytes............................303104  
  14. Last Used Ext FileId....................5  
  15. Last Used Ext BlockId...................20608  
  16. Last Used Block.........................91  
  17. Blocks under HWM........................219  
  18. ...  
  19.   
  20. PL/SQL procedure successfully completed.  

TRUNCATE will cause the data object be re-allocated. Perform full table scan on it again.

SQL代码
  1. D:\HelloDBA.COM\perl scripts>perl getsqlstats.pl  
  2. tnsname (default is orcl):  
  3. user name (default is demo):  
  4. password:  
  5. Array size (Default is 32):  
  6. Execution plan format (Default is TYPICAL):  
  7. SQL to be executed (without ;):  
  8. select * from dummy_obj  
  9.   
  10. Seesion ID: 16  Process ID: 3260  
  11. SQL Prepared. Process paused, press ENTER to continue...  
  12. SQL is executing ...  
  13. SQL Executed. Process Paused, press ENTER to continue...  
  14.   
  15. statistics  
  16. -----------------------------------------  
  17. consistent changes: 0  
  18. consistent gets: 780  
  19. consistent gets direct: 770  
  20. consistent gets from cache: 10  
  21. db block changes: 1  
  22. db block gets: 1  
  23. db block gets direct: 0  
  24. db block gets from cache: 1  
  25. physical reads: 212  
  26. physical reads cache: 5  
  27. physical reads direct: 207  
  28. physical writes: 0  
  29. physical writes direct: 0  
  30. recursive calls: 20  
  31. session logical reads: 781  

Now, Direct IO auto tuning is effective. Data blocks were read directly from disk bypassing buffer cache, and only the segment header was read into buffer cache. But, if we perform FTS again ...

SQL代码
  1. D:\HelloDBA.COM\perl scripts>perl getsqlstats.pl  
  2. tnsname (default is orcl):  
  3. user name (default is demo):  
  4. password:  
  5. Array size (Default is 32):  
  6. Execution plan format (Default is TYPICAL):  
  7. SQL to be executed (without ;):  
  8. select * from dummy_obj  
  9.   
  10. Seesion ID: 16  Process ID: 4104  
  11. SQL Prepared. Process paused, press ENTER to continue...  
  12. SQL is executing ...  
  13. SQL Executed. Process Paused, press ENTER to continue...  
  14.   
  15. statistics  
  16. -----------------------------------------  
  17. consistent changes: 0  
  18. consistent gets: 775  
  19. consistent gets direct: 0  
  20. consistent gets from cache: 775  
  21. db block changes: 1  
  22. db block gets: 0  
  23. db block gets direct: 0  
  24. db block gets from cache: 0  
  25. physical reads: 207  
  26. physical reads cache: 207  
  27. physical reads direct: 0  
  28. physical writes: 0  
  29. physical writes direct: 0  
  30. recursive calls: 0  
  31. session logical reads: 775  

Noted that the data blocks were read into buffer cache. Oracle keep on operating such behaviors untill we increased the number of blocks to 1091 ( just larger than _small_table_threshold*5).

SQL代码
  1. HELLODBA.COM>truncate table dummy_obj;  
  2.   
  3. Table truncated.  
  4.   
  5. HELLODBA.COM>insert /*+append*/into dummy_obj select a.* from t_objects a, t_objects b where rownum<=96300;  
  6.   
  7. 96300 rows created.  
  8.   
  9. HELLODBA.COM>commit;  
  10.   
  11. Commit complete.  
  12.   
  13. HELLODBA.COM>exec dba_seg_info('DUMMY_OBJ');  
  14. Total Blocks............................1152  
  15. Total Bytes.............................9437184  
  16. Unused Blocks...........................61  
  17. Unused Bytes............................499712  
  18. Last Used Ext FileId....................5  
  19. Last Used Ext BlockId...................22784  
  20. Last Used Block.........................67  
  21. Blocks under HWM........................1091  
  22. ...  
  23.   
  24. PL/SQL procedure successfully completed.  

We could note thing is changed.

SQL代码
  1. D:\HelloDBA.COM\perl scripts>perl getsqlstats.pl  
  2. tnsname (default is orcl):  
  3. user name (default is demo):  
  4. password:  
  5. Array size (Default is 32):  
  6. Execution plan format (Default is TYPICAL):  
  7. SQL to be executed (without ;):  
  8. select * from dummy_obj  
  9.   
  10. Seesion ID: 16  Process ID: 4056  
  11. SQL Prepared. Process paused, press ENTER to continue...  
  12. SQL is executing ...  
  13. SQL Executed. Process Paused, press ENTER to continue...  
  14.   
  15. statistics  
  16. -----------------------------------------  
  17. consistent changes: 0  
  18. consistent gets: 3955  
  19. consistent gets direct: 3951  
  20. consistent gets from cache: 4  
  21. db block changes: 0  
  22. db block gets: 0  
  23. db block gets direct: 0  
  24. db block gets from cache: 0  
  25. physical reads: 1065  
  26. physical reads cache: 0  
  27. physical reads direct: 1065  
  28. physical writes: 0  
  29. physical writes direct: 0  
  30. recursive calls: 0  
  31. session logical reads: 3955  

No matter how many times we performed FTS on it, data blocks were always read diretly bypassing buffer cache.

And now, even if we set the "_small_table_threshold" to a large number (less than Number of Blocks), the behavior will not change.

SQL代码
  1. D:\HelloDBA.COM\perl scripts>perl getsqlstats.pl  
  2. tnsname (default is orcl):  
  3. user name (default is demo):  
  4. password:  
  5. Array size (Default is 32):  
  6. Execution plan format (Default is TYPICAL):  
  7. Pre-executed SQLs:  
  8. alter session set "_small_table_threshold" = 1090... ok  
  9. SQL to be executed (without ;):  
  10. select * from dummy_obj  
  11.   
  12. Seesion ID: 142 Process ID: 5760  
  13. SQL Prepared. Process paused, press ENTER to continue...  
  14. SQL is executing ...  
  15. SQL Executed. Process Paused, press ENTER to continue...  
  16.   
  17. statistics  
  18. -----------------------------------------  
  19. consistent changes: 0  
  20. consistent gets: 3955  
  21. consistent gets direct: 3951  
  22. consistent gets from cache: 4  
  23. db block changes: 0  
  24. db block gets: 0  
  25. db block gets direct: 0  
  26. db block gets from cache: 0  
  27. physical reads: 1065  
  28. physical reads cache: 0  
  29. physical reads direct: 1065  
  30. physical writes: 0  
  31. physical writes direct: 0  
  32. recursive calls: 0  
  33. session logical reads: 3955  

I suppose it because oracle has marked this segment as "NOCACHE" object in the buffer when found it's a "large" table.

But wait... Let's turn off Direct IO Auto Tunning off (set event 10949 as level 1), which will force the data blocks cached.

SQL代码
  1. D:\HelloDBA.COM\perl scripts>perl getsqlstats.pl  
  2. tnsname (default is orcl):  
  3. user name (default is demo):  
  4. password:  
  5. Array size (Default is 32):  
  6. Execution plan format (Default is TYPICAL):  
  7. Pre-executed SQLs:  
  8. alter session set events '10949 trace name context forever, level 1'... ok  
  9. SQL to be executed (without ;):  
  10. select * from dummy_obj  
  11.   
  12. Seesion ID: 141 Process ID: 5016  
  13. SQL Prepared. Process paused, press ENTER to continue...  
  14. SQL is executing ...  
  15. SQL Executed. Process Paused, press ENTER to continue...  
  16.   
  17. statistics  
  18. -----------------------------------------  
  19. consistent changes: 0  
  20. consistent gets: 3957  
  21. consistent gets direct: 0  
  22. consistent gets from cache: 3957  
  23. db block changes: 1  
  24. db block gets: 0  
  25. db block gets direct: 0  
  26. db block gets from cache: 0  
  27. physical reads: 1065  
  28. physical reads cache: 1065  
  29. physical reads direct: 0  
  30. physical writes: 0  
  31. physical writes direct: 0  
  32. recursive calls: 0  
  33. session logical reads: 3957  

Then turn this feature on again,

SQL代码
  1. D:\HelloDBA.COM\perl scripts>perl getsqlstats.pl  
  2. tnsname (default is orcl):  
  3. user name (default is demo):  
  4. password:  
  5. Array size (Default is 32):  
  6. Execution plan format (Default is TYPICAL):  
  7. Pre-executed SQLs:  
  8. alter session set events '10949 trace name context forever, level 0'... ok  
  9. SQL to be executed (without ;):  
  10. select * from dummy_obj  
  11.   
  12. Seesion ID: 136 Process ID: 5176  
  13. SQL Prepared. Process paused, press ENTER to continue...  
  14. SQL is executing ...  
  15. SQL Executed. Process Paused, press ENTER to continue...  
  16.   
  17. statistics  
  18. -----------------------------------------  
  19. consistent changes: 0  
  20. consistent gets: 3957  
  21. consistent gets direct: 0  
  22. consistent gets from cache: 3957  
  23. db block changes: 1  
  24. db block gets: 0  
  25. db block gets direct: 0  
  26. db block gets from cache: 0  
  27. physical reads: 0  
  28. physical reads cache: 0  
  29. physical reads direct: 0  
  30. physical writes: 0  
  31. physical writes direct: 0  
  32. recursive calls: 0  
  33. session logical reads: 3957  

We could find that data blocks were read from buffer cache.

However, the story is not end. Let's change the very large object size percent setting (_very_large_object_threshold, also introduced in 11g) just below number of blocks of our testing table (1091/10912 = 0.0999) in the session.

SQL代码
  1. D:\HelloDBA.COM\perl scripts>perl getsqlstats.pl  
  2. tnsname (default is orcl):  
  3. user name (default is demo):  
  4. password:  
  5. Array size (Default is 32):  
  6. Execution plan format (Default is TYPICAL):  
  7. Pre-executed SQLs:  
  8. alter session set "_very_large_object_threshold" = 9... ok  
  9. SQL to be executed (without ;):  
  10. select * from dummy_obj  
  11.   
  12. Seesion ID: 141 Process ID: 4256  
  13. SQL Prepared. Process paused, press ENTER to continue...  
  14. SQL is executing ...  
  15. SQL Executed. Process Paused, press ENTER to continue...  
  16.   
  17. statistics  
  18. -----------------------------------------  
  19. consistent changes: 0  
  20. consistent gets: 3955  
  21. consistent gets direct: 3951  
  22. consistent gets from cache: 4  
  23. db block changes: 0  
  24. db block gets: 0  
  25. db block gets direct: 0  
  26. db block gets from cache: 0  
  27. physical reads: 1065  
  28. physical reads cache: 0  
  29. physical reads direct: 1065  
  30. physical writes: 0  
  31. physical writes direct: 0  
  32. recursive calls: 0  
  33. session logical reads: 3955  

DUMMY_OBJ is now treated as "very large object" by oracle, and its data blocks will not be read into/from buffer cache.

Note: Even though data blocks were read directly due to the very large object threshold, those cached data blocks were not flushed out from buffer cache. Once we change the threshold and the table become a normal size table again, oracle will still read those cached data blocks.

Note(2): It will NOT be treated as "very large object" if its block number less than _small_table_threshold*5.

Now, is it the end? Nope, we'd like to involve another feature --- Serial Direct Read (who is not new). We reduce the size of testing to a very small figure,

SQL代码
  1. HELLODBA.COM>drop table dummy_obj;  
  2.   
  3. Table dropped.  
  4.   
  5. HELLODBA.COM>create table dummy_obj as  select a.* from t_objects a, t_objects b where rownum<=1000;  
  6.   
  7. Table created.  
  8.   
  9. HELLODBA.COM>exec dbms_stats.gather_table_stats('DEMO','DUMMY_OBJ');  
  10.   
  11. PL/SQL procedure successfully completed.  
  12.   
  13. HELLODBA.COM>exec dbms_stats.gather_table_stats('DEMO','DUMMY_OBJ');  
  14.   
  15. PL/SQL procedure successfully completed.  
  16.   
  17. HELLODBA.COM>exec dba_seg_info('DUMMY_OBJ');  
  18. Total Blocks............................16  
  19. Total Bytes.............................131072  
  20. Unused Blocks...........................2  
  21. Unused Bytes............................16384  
  22. Last Used Ext FileId....................5  
  23. Last Used Ext BlockId...................20280  
  24. Last Used Block.........................6  
  25. Blocks under HWM........................14  
  26.  *************************************************  
  27. The segment is analyzed  
  28. 0% -- 25% free space blocks.............0  
  29. 0% -- 25% free space bytes..............0  
  30. 25% -- 50% free space blocks............0  
  31. 25% -- 50% free space bytes.............0  
  32. 50% -- 75% free space blocks............0  
  33. 50% -- 75% free space bytes.............0  
  34. 75% -- 100% free space blocks...........0  
  35. 75% -- 100% free space bytes............0  
  36. Unused Blocks...........................0  
  37. Unused Bytes............................0  
  38. Total Blocks............................11  
  39. Total bytes.............................90112  
  40.   
  41. PL/SQL procedure successfully completed.  

Then turn on this feature in the session of FTS,

SQL代码
  1. D:\HelloDBA.COM\perl scripts>perl getsqlstats.pl  
  2. tnsname (default is orcl):  
  3. user name (default is demo):  
  4. password:  
  5. Array size (Default is 32):  
  6. Execution plan format (Default is TYPICAL):  
  7. Pre-executed SQLs:  
  8. alter session set "_serial_direct_read" = true... ok  
  9. SQL to be executed (without ;):  
  10. select * from dummy_obj  
  11.   
  12. Seesion ID: 136 Process ID: 2152  
  13. SQL Prepared. Process paused, press ENTER to continue...  
  14. SQL is executing ...  
  15. SQL Executed. Process Paused, press ENTER to continue...  
  16.   
  17. statistics  
  18. -----------------------------------------  
  19. consistent changes: 0  
  20. consistent gets: 44  
  21. consistent gets direct: 41  
  22. consistent gets from cache: 3  
  23. db block changes: 0  
  24. db block gets: 0  
  25. db block gets direct: 0  
  26. db block gets from cache: 0  
  27. physical reads: 11  
  28. physical reads cache: 0  
  29. physical reads direct: 11  
  30. physical writes: 0  
  31. physical writes direct: 0  
  32. recursive calls: 1  
  33. session logical reads: 44  

What happed? No matter how many blocks in the table, they were read directly where performing full table scan on it. And this feature has higher priority than Direct IO Auto Tune.

Now, let's terminal our testing and recovery environment of the session (turn Serial Direct Read off).

SQL代码
  1. D:\HelloDBA.COM\perl scripts>perl getsqlstats.pl  
  2. tnsname (default is orcl):  
  3. user name (default is demo):  
  4. password:  
  5. Array size (Default is 32):  
  6. Execution plan format (Default is TYPICAL):  
  7. Pre-executed SQLs:  
  8. alter session set "_serial_direct_read" = false... ok  
  9. SQL to be executed (without ;):  
  10. select * from dummy_obj  
  11.   
  12. Seesion ID: 140 Process ID: 2792  
  13. SQL Prepared. Process paused, press ENTER to continue...  
  14. SQL is executing ...  
  15. SQL Executed. Process Paused, press ENTER to continue...  
  16.   
  17. statistics  
  18. -----------------------------------------  
  19. consistent changes: 0  
  20. consistent gets: 44  
  21. consistent gets direct: 41  
  22. consistent gets from cache: 3  
  23. db block changes: 0  
  24. db block gets: 0  
  25. db block gets direct: 0  
  26. db block gets from cache: 0  
  27. physical reads: 11  
  28. physical reads cache: 0  
  29. physical reads direct: 11  
  30. physical writes: 0  
  31. physical writes direct: 0  
  32. recursive calls: 0  
  33. session logical reads: 44  

Oops, data blocks can not be cached any longer. Perhaps the segment has been marked as special type, which will cause oracle read data blocks directly. And once we flush the segment out from buffer cache, the behavior became normal.

To summary this feature, I write the procedure in pseudo-code.

SQL代码
  1. Read segment header;  
  2. Get #blocks under high water mark;  
  3. IF (Serial Direct Read is on)  
  4.   read data blocks from disk directly;  
  5. ELSE IF (#blocks <= Small Table Threshold) THEN  
  6.   IF (data blocks are cached) THEN  
  7.     read from cache;  
  8.   ELSE  
  9.     read data blocks from disk into cache;  
  10.   END IF  
  11. ELSE IF (#blocks > Small Table Threshold AND #blocks <= Small Table Threshold * 5) THEN  
  12.   IF segment header is not cached THEN  
  13.     IF (data blocks are cached) THEN  
  14.       read from cache;  
  15.     ELSE  
  16.       read data blocks from disk directly  
  17.     END IF  
  18.   ELSE   
  19.     read data blocks from disk into cache  
  20.   END IF  
  21. ELSE  
  22.   IF (data blocks are not cached AND #blocks <= Very Large Object Threshold/100 * Number of Buffer Blocks) THEN  
  23.     read from cache;  
  24.   ELSE  
  25.     read data blocks from disk directly;  
  26.   END IF  
  27. END IF  

--- Fuyuncat ---

Top

Copyright ©2005, HelloDBA.Com All reseverd.

Declaration
by fuyuncat