博学,审问,慎思,明辨,笃行

导航

Oracle 理清全表扫描和高水位,行预取的关系(转)

转自:http://blog.csdn.net/dba_waterbin/article/details/8563249

以前写过一篇博客,调侃了一下全表扫,今天继续,感觉对全表扫的认识还是不够:侃侃全表扫

 

        ㈠ 全表扫描与HWM
        
        在Table Access Full中,数据库引擎顺次读取表在HWM下的所有数据块
        全表扫描可能是不够理想,特别是表包含大量空的或者接近空的块时
        很明显,一个块必须先读才能知道它是否包含数据
        当表的删除操作比插入操作多的时候,最容易导致表包含许多稀疏的数据块
        所以,逻辑读依赖于块的数量而非行数
        测试如下:

 

  1. hr@ORCL> select /*+ full(t) */ * from t where object_id=51;  
  2.   
  3. Execution Plan  
  4. ----------------------------------------------------------  
  5. Plan hash value: 1601196873  
  6.   
  7. --------------------------------------------------------------------------  
  8. | Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |  
  9. --------------------------------------------------------------------------  
  10. |   0 | SELECT STATEMENT  |      |     1 |    87 |   160   (2)| 00:00:02 |  
  11. |*  1 |  TABLE ACCESS FULL| T    |     1 |    87 |   160   (2)| 00:00:02 |  
  12. --------------------------------------------------------------------------  
  13.   
  14.    
  15.    
  16. hr@ORCL> set autot trace stat  
  17. hr@ORCL> select * from t where object_id=51;  
  18.   
  19.   
  20. Statistics  
  21. ----------------------------------------------------------  
  22.           0  recursive calls  
  23.           0  db block gets  
  24.         698  consistent gets  
  25.         335  physical reads  
  26.           0  redo size  
  27.        1199  bytes sent via SQL*Net to client  
  28.         385  bytes received via SQL*Net from client  
  29.           2  SQL*Net roundtrips to/from client  
  30.           0  sorts (memory)  
  31.           0  sorts (disk)  
  32.           1  rows processed  
  33.   
  34. hr@ORCL> delete t where object_id <> 51;  
  35.   
  36. 50321 rows deleted.  
  37.   
  38. hr@ORCL> select * from t where object_id=51;--此时会对许多完全空的块进行无效的访问  
  39.   
  40.   
  41. Statistics  
  42. ----------------------------------------------------------  
  43.           0  recursive calls  
  44.           0  db block gets  
  45.         698  consistent gets  ---查询所需的逻辑读并没有改变  
  46.           0  physical reads  
  47.           0  redo size  
  48.        1199  bytes sent via SQL*Net to client  
  49.         385  bytes received via SQL*Net from client  
  50.           2  SQL*Net roundtrips to/from client  
  51.           0  sorts (memory)  
  52.           0  sorts (disk)  
  53.           1  rows processed  
  54.   
  55. --要降低高水位线,有必要对表进行重组  
  56. hr@ORCL> alter table t enable row movement; --行迁移必须先激活,因为重组过程中有新的rowid产生  
  57.   
  58. Table altered.  
  59.   
  60. hr@ORCL> alter table t shrink space;  
  61.   
  62. Table altered.  
  63.   
  64. hr@ORCL> select * from t where object_id=51;  
  65.   
  66.   
  67. Statistics  
  68. ----------------------------------------------------------  
  69.         179  recursive calls  
  70.           0  db block gets  
  71.          26  consistent gets  --此时查询所需的逻辑读变成26个  
  72.           5  physical reads  
  73.           0  redo size  
  74.        1199  bytes sent via SQL*Net to client  
  75.         385  bytes received via SQL*Net from client  
  76.           2  SQL*Net roundtrips to/from client  
  77.           4  sorts (memory)  
  78.           0  sorts (disk)  
  79.           1  rows processed  


       ㈡ 全表扫描与行预取
       
       全表扫描的逻辑读严重依赖于行预取的设置
       下面Think和大家一起谈谈行预取对全表扫描的逻辑读的影响
       简单而言,数据库引擎每访问一个数据块就产生一个逻辑读
       对于全表扫描,存在两种极端:
       如果行预取设定为1,则每个返回行相当于一个逻辑读
       如果行预取设定比每个表的单块存储行数都大,逻辑读的数量就和表的块数量接近 
       测试:

 

 

  1. hr@ORCL> ed  
  2. Wrote file afiedt.buf  
  3.   
  4.   1  select num_rows,blocks,round(num_rows/blocks) as rows_per_block  
  5.   2    from user_tables  
  6.   3*  where table_name='T'  
  7. hr@ORCL> /  
  8.   
  9.   NUM_ROWS     BLOCKS ROWS_PER_BLOCK  
  10. ---------- ---------- --------------  
  11.      50323        712             71  --T表每个块平均有71行  
  12.        
  13. hr@ORCL> set autot trace stat  
  14. hr@ORCL> set arraysize 2  
  15. hr@ORCL> select * from t;  
  16.   
  17. 50323 rows selected.  
  18.   
  19.   
  20. Statistics  
  21. ----------------------------------------------------------  
  22.           1  recursive calls  
  23.           0  db block gets  
  24.       25532  consistent gets  
  25.           0  physical reads  
  26.           0  redo size  
  27.     8236771  bytes sent via SQL*Net to client  
  28.      277156  bytes received via SQL*Net from client  
  29.       25163  SQL*Net roundtrips to/from client     --[返回行的总数/arraysize]+1  
  30.           0  sorts (memory)  
  31.           0  sorts (disk)  
  32.       50323  rows processed  
  33.   
  34. hr@ORCL> set arraysize 3000  
  35. hr@ORCL> select * from t;  
  36.   
  37. 50323 rows selected.  
  38.   
  39.   
  40. Statistics  
  41. ----------------------------------------------------------  
  42.           0  recursive calls  
  43.           0  db block gets  
  44.         714  consistent gets  
  45.           0  physical reads  
  46.           0  redo size  
  47.     4967955  bytes sent via SQL*Net to client  
  48.         561  bytes received via SQL*Net from client  
  49.          18  SQL*Net roundtrips to/from client  
  50.           0  sorts (memory)  
  51.           0  sorts (disk)  
  52.       50323  rows processed  


       当行预取设定为2,逻辑读的数量(25532)大概是行数(50323)的一半
       当行预取设定比平均每个块中的行数(71)都要高,逻辑读的数量(714)和总块数(712)接近

posted on 2014-04-20 21:20  pengdaijun  阅读(230)  评论(0编辑  收藏  举报