Dextrys DBA's space

10.2版本CBO计算中的基数问题

上一篇 / 下一篇  2008-03-28 15:21:50

查看( 192 ) / 评论( 11 )
最近在看LEWIS的基于成本的优化,发现一个小的问题,
书中是采用的10.1做了很多的DEMO,
其中一个衡量SQL语句的优化的重要指标是基数值(CARD值),
但是在10.2版本了,Card值没有了,取而代之的是ROWS值,
是不是10.2的CBO发生了大的调整,取消了基数值的概念,
并且可以准确的计算出实际的数据的行数?
这样一来很多基于基数值的优化法则是不是就不准确了?

TAG:

棉花糖ONE发布于2008-03-28 15:49:07
不至于吧,要是按照作者的脚本做测试,得到的结果应该和书上的类似
anlinew的个人空间 anlinew 发布于2008-03-28 15:57:51
一回事,可能oracle为了更易懂吧
litterbaby发布于2008-03-28 16:05:07
其实LEWIS在书上就说了就是一回事
太极虫的个人空间 kelsoncong 发布于2008-03-28 16:22:40
书上有一个数据类型的例子,
分别用了date,int和char类型的字段表示日期,
然后分别用这三个字段做条件进行筛选,
最后证明用date类型的得到的基数最小,因此证明用日期类型表示日期最好,
但是在10.2的数据库上所得到的rows的值全部一样,都等于实际筛选出来的记录条数,
因此row和card应该不是一个东西
PS:LEWIS写书的时候,oracle 最高版本是10.1.0.4
suniori的个人空间 suniori 发布于2008-03-28 16:24:41
我觉得CARD 和ROW 是一回事,名字不一样而已,你也可以叫他COUNT
太极虫的个人空间 kelsoncong 发布于2008-03-28 16:30:00
SQL>
SQL> select        *
  2  from        t1
  3  where         d1 between to_date('30-12-2002','dd-mm-yyyy')
  4             and     to_date('05-01-2003','dd-mm-yyyy')
  5  ;

已选择7行。


执行计划
----------------------------------------------------------                     
Plan hash value: 3617692013                                                     
                                                                                
----------------------------------------------------------                     
| Id  | Operation         | Name | Rows  | Bytes | Cost  |                     
----------------------------------------------------------                     
|   0 | SELECT STATEMENT  |      |     7 |   196 |     3 |                     
|*  1 |  TABLE ACCESS FULL| T1   |     7 |   196 |     3 |                     
----------------------------------------------------------                     
                                                                                
Predicate Information (identified by operation id):                             
---------------------------------------------------                             
                                                                                
   1 - filter("D1">=TO_DATE('2002-12-30 00:00:00', 'yyyy-mm-dd                  
              hh24:mi:ss') AND "D1"<=TO_DATE('2003-01-05 00:00:00', 'yyyy-mm-dd
              hh24:mi:ss'))                                                     
                                                                                
Note                                                                           
-----                                                                           
   - cpu costing is off (consider enabling it)                                 
   - dynamic sampling used for this statement                                   


统计信息
----------------------------------------------------------                     
        169  recursive calls                                                   
          0  db block gets                                                      
         52  consistent gets                                                   
          2  physical reads                                                     
          0  redo size                                                         
        725  bytes sent via SQL*Net to client                                   
        385  bytes received via SQL*Net from client                             
          2  SQL*Net roundtrips to/from client                                 
          4  sorts (memory)                                                     
          0  sorts (disk)                                                      
          7  rows processed                                                     

SQL> select        *
  2  from        t1
  3  where         n1 between 20021230 and 20030105
  4  ;

已选择7行。


执行计划
----------------------------------------------------------                     
Plan hash value: 3617692013                                                     
                                                                                
----------------------------------------------------------                     
| Id  | Operation         | Name | Rows  | Bytes | Cost  |                     
----------------------------------------------------------                     
|   0 | SELECT STATEMENT  |      |     7 |   196 |     3 |                     
|*  1 |  TABLE ACCESS FULL| T1   |     7 |   196 |     3 |                     
----------------------------------------------------------                     
                                                                                
Predicate Information (identified by operation id):                             
---------------------------------------------------                             
                                                                                
   1 - filter("N1">=20021230 AND "N1"<=20030105)                                
                                                                                
Note                                                                           
-----                                                                           
   - cpu costing is off (consider enabling it)                                 
   - dynamic sampling used for this statement                                   


统计信息
----------------------------------------------------------                     
          5  recursive calls                                                   
          0  db block gets                                                      
         34  consistent gets                                                   
          0  physical reads                                                     
          0  redo size                                                         
        725  bytes sent via SQL*Net to client                                   
        385  bytes received via SQL*Net from client                             
          2  SQL*Net roundtrips to/from client                                 
          0  sorts (memory)                                                     
          0  sorts (disk)                                                      
          7  rows processed                                                     

SQL> select        *
  2  from        t1
  3  where         v1 between '20021230' and '20030105'
  4  ;

已选择7行。


执行计划
----------------------------------------------------------                     
Plan hash value: 3617692013                                                     
                                                                                
----------------------------------------------------------                     
| Id  | Operation         | Name | Rows  | Bytes | Cost  |                     
----------------------------------------------------------                     
|   0 | SELECT STATEMENT  |      |     7 |   196 |     3 |                     
|*  1 |  TABLE ACCESS FULL| T1   |     7 |   196 |     3 |                     
----------------------------------------------------------                     
                                                                                
Predicate Information (identified by operation id):                             
---------------------------------------------------                             
                                                                                
   1 - filter("V1">='20021230' AND "V1"<='20030105')                           
                                                                                
Note                                                                           
-----                                                                           
   - cpu costing is off (consider enabling it)                                 
   - dynamic sampling used for this statement                                   


统计信息
----------------------------------------------------------                     
          5  recursive calls                                                   
          0  db block gets                                                      
         34  consistent gets                                                   
          0  physical reads                                                     
          0  redo size                                                         
        725  bytes sent via SQL*Net to client                                   
        385  bytes received via SQL*Net from client                             
          2  SQL*Net roundtrips to/from client                                 
          0  sorts (memory)                                                     
          0  sorts (disk)                                                      
          7  rows processed                                                     

SQL> spool out
太极虫的个人空间 kelsoncong 发布于2008-03-28 16:31:37
看看这个例子,所有的rows的值都是7,都等于实际取得的值rows processed
按照CBO书的介绍,这三种写法的card值应该不一样的
棉花糖ONE发布于2008-03-28 17:02:15
这问题可能是10.2处理掉了吧,你把optimizer_features_enable改成'9.2.0'看看结果
OracleForEver ihekoko 发布于2008-03-28 18:22:56
楼主
你说的这一章 作者主要是想证明采用合适的数据类型可以防止oracle选择奇怪的执行计划

你所建立的表的数据很可能和作者测试用的表有很大的区别

比如 某个表中存储的是一年的相关数据 每个月的数据都很平均
对于日期类型的 d1 between to_date('01-01-2007','dd-mm-yyyy') and   to_ate('01-02-2007','dd-mm-yyyy')
oracle 很容易的就知道这里的Card(rows)大概会是 numrows/12(一年中的一个月)
但是 数字类型的 n1 between 20070101 and 20070201  ( (20070201-20070101)/(max_value-min_value))
或者字符类型的 v1 between '20070101' and '20070201' (('20070201'-'20070101')/(max_value-min_value))
oracle  很有可能就得到一个“错误”的Card(rows)
于是采用了一个我们看起来奇怪的执行计划

这里所谓的错误 只是oracle根据它自己的算法算出的card(rows)并不是我们想的那样
太极虫的个人空间 kelsoncong 发布于2008-03-31 09:01:12
多谢几位的建议,我用的例子就是书上提供的,环境也完全一样的,
我按照棉花糖的指示调整了一下
optimizer_features_enable
发现结果和书上的就几乎一样了,
看来oracle 10.2对优化器这一块做了不小的调整,修正了很多问题,使的基数值更加的准确,几乎和实际的值相同
(这可能也是oracle把card修改成row的原因吧)
太极虫的个人空间 kelsoncong 发布于2008-03-31 09:01:37
再次感谢几位的帮助!
我来说两句

(可选)

日历

« 2008-10-12  
   1234
567891011
12131415161718
19202122232425
262728293031 

数据统计

  • 访问量: 810
  • 日志数: 1025
  • 图片数: 1
  • 建立时间: 2008-02-02
  • 更新时间: 2008-09-08

RSS订阅

Open Toolbar