当使用CBO模式的优化器时,oracle在生成查询计划时,会计算各个访问路径的代价,选择代价最小的访问路径作为查询计划。这个选择过程我们可以通过做一个10053的trace来观察。

在做代价估算时,有一个很重要的参数作为代价计算的因数,这就扫描字段的集的势(cardinality)。那么这个值是如何计算的呢?这个值的计算根据索引情况及查询条件不同而不同,因而它的计算也比较复杂。下面我们只讨论在使用绑定变量的情况下集的势的计算。

集的势总的计算公式是:

集的势 = MAX(集的势因子 * 记录数, 1)

可以看出,影响集的势的值的主要因素是集的势因子。在不同情况下,这个因子的计算公式不同,下面我们就讨论不同情况下的集的势因子的计算。

索引字段

对于建立了索引(可以是复合索引)的字段,如果查询条件是“=”,字段的集的势计算公式如下:

集的势因子 = 1 / 字段上的唯一值数

让我们做个测试看,

SQL> create table T_PEEKING3 (a NUMBER, b char(1), c char(5));
 
Table created.
 
SQL>
SQL> create index T_PEEKING3_IDX1 on T_PEEKING3(b, c);
 
Index created.
 
SQL>
SQL> begin
  2    for i in 1..1000 loop
  3      insert into T_PEEKING3 values (i, mod(i, 10), mod(i, 13));
  4    end loop;
  5    commit;
  6  end;
  7  /
 
PL/SQL procedure successfully completed.
 
SQL>
SQL> analyze table T_PEEKING3 compute statistics for table for all indexes for all indexed columns;
 
Table analyzed.

表的记录数为1000,字段(B, C)上建立了索引,它们的唯一值数分别为:

SQL> select count(distinct b) from T_PEEKING3;
 
COUNT(DISTINCTB)
----------------
              10
 
SQL>
SQL> select count(distinct c) from T_PEEKING3;
 
COUNT(DISTINCTC)
----------------
              13
 
SQL>
SQL> select count(*) from
  2  (
  3  select distinct b, c from T_PEEKING3
  4  );
 
  COUNT(*)
----------
       130

因此,B字段的集的势为round(1/10 * 1000) = 100,

select /*+index(a T_PEEKING3_IDX1)*/ * from T_PEEKING3 a where b=:V;
 
SELECT STATEMENT, GOAL = CHOOSE                     Cost=55  Cardinality=100   Bytes=1500
 TABLE ACCESS BY INDEX ROWID       Object name=T_PEEKING3    Cost=55  Cardinality=100  Bytes=1500
  INDEX RANGE SCAN        Object name=T_PEEKING3_IDX1        Cost=1   Cardinality=100  

因此,C字段的集的势为round(1/13 * 1000) = 77,

select /*+index(a T_PEEKING3_IDX1)*/ * from T_PEEKING3 a where c=:V;
 
SELECT STATEMENT, GOAL = CHOOSE                     Cost=21  Cardinality=77    Bytes=1386
 TABLE ACCESS BY INDEX ROWID Object name=T_PEEKING3 Cost=21  Cardinality=77    Bytes=1386
  INDEX FULL SCAN Object name=T_PEEKING3_IDX1       Cost=3   Cardinality=77    

 

 

 

如果索引字段查询条件是“<”“>”“<=”“>=”,则计算公式为,

集的势因子 = (1 / 字段上的唯一值数) + (1/记录数)

 

例:当查询条件为c > :1,它的集的势为round((1/13 + 1/1000)*1000) = 78

select /*+index(a T_PEEKING3_IDX1)*/* from T_PEEKING3 a where c > :1
 
SELECT STATEMENT, GOAL = CHOOSE                     Cost=22  Cardinality=78    Bytes=1404
 TABLE ACCESS BY INDEX ROWID Object name=T_PEEKING3 Cost=22  Cardinality=78    Bytes=1404
  INDEX FULL SCAN Object name=T_PEEKING3_IDX1       Cost=3   Cardinality=78             

如果索引字段查询条件是in,则计算公式为,

集的势因子 = in条件中的变量数 / 字段上的唯一值数

 

例:当查询条件为c in (:1, :2, :3),它的集的势为round(3/13 * 1000) = 231

select /*+index(a T_PEEKING3_IDX1)*/* from T_PEEKING3 a where  c in (:1, :2, :3);
 
SELECT STATEMENT, GOAL = CHOOSE                     Cost=57  Cardinality=231   Bytes=4158
 TABLE ACCESS BY INDEX ROWID Object name=T_PEEKING3 Cost=57  Cardinality=231   Bytes=4158
  INDEX FULL SCAN Object name=T_PEEKING3_IDX1       Cost=3   Cardinality=231   

如果索引字段查询条件是“<>”,则计算公式为,

集的势因子 = (1 – (1/字段上的唯一值数))

这时的集的势值也是这个字段上可以达到的最大集的势值。

例:当查询条件为c <> :1,它的集的势为round((1 – 1/13) * 1000) = 923

select /*+index(a T_PEEKING3_IDX1)*/* from T_PEEKING3 a where  c <> :1
 
SELECT STATEMENT, GOAL = CHOOSE                     Cost=219 Cardinality=923   Bytes=16614
 TABLE ACCESS BY INDEX ROWID Object name=T_PEEKING3 Cost=219 Cardinality=923   Bytes=16614
  INDEX FULL SCAN Object name=T_PEEKING3_IDX1       Cost=3   Cardinality=923   

当查询条件为not in时,计算就更为复杂了。它是根据not in中的变量值按阶计算的。

集的势因子 = (1 – (1/字段上的唯一值数))^(not in中变量数)

例:当查询条件为c not in (:1, :2, :3),它的集的势为round((1 – 1/13)^3 * 1000) = 787

select /*+index(a T_PEEKING3_IDX1)*/* from T_PEEKING3 a where  c not in (:1, :2, :3)
 
SELECT STATEMENT, GOAL = CHOOSE                     Cost=187 Cardinality=787   Bytes=14166
 TABLE ACCESS BY INDEX ROWID Object name=T_PEEKING3 Cost=187 Cardinality=787   Bytes=14166
  INDEX FULL SCAN Object name=T_PEEKING3_IDX1       Cost=3   Cardinality=787   

非索引字段

当查询条件为 “=”、“in” 时,非索引字段的集的势因子是,

集的势因子 = 1/100

例:以下集的势为 1/100 * 1000 = 10

select * from T_PEEKING3 where a = :1;
SELECT STATEMENT, GOAL = CHOOSE                     Cost=2   Cardinality=10    Bytes=180
 TABLE ACCESS FULL Object name=T_PEEKING3   Cost=2   Cardinality=10    Bytes=180

当查询条件为“<”、“>”、“<=”、“>=”、“<>”、“not in” 时,非索引字段的集的势因子是,

集的势因子 = 1/20

例:以下集的势为 1/100 * 1000 = 10

select * from T_PEEKING3 where a < :1;
SELECT STATEMENT, GOAL = CHOOSE                     Cost=2   Cardinality=10    Bytes=180
 TABLE ACCESS FULL Object name=T_PEEKING3   Cost=2   Cardinality=50    Bytes=180

多字段

对于多个字段同时在查询条件中,集的势因子计算公式如下,

集的势因子 = 字段1的集的势因子 * 字段2的集的势因子 * … *字段n的集的势因子

例:以下两个字段的复合集的势为round(((1/10 + 1/1000)*(1/13)) * 1000) = 8,

select /*+index(a T_PEEKING3_IDX1)*/* from T_PEEKING3 a where  b > :1 and c = :2;
SELECT STATEMENT, GOAL = CHOOSE             Cost=4   Cardinality=8     Bytes=144
 TABLE ACCESS BY INDEX ROWID Object name=T_PEEKING3 Cost=4   Cardinality=8     Bytes=144
  INDEX RANGE SCAN        Object name=T_PEEKING3_IDX1        Cost=1   Cardinality=8             

例:以下查询的集的势为round(((3/10) * 1/13) * 1000) = 23

select /*+index(a T_PEEKING3_IDX1)*/* from T_PEEKING3 a where  b in (:1, :2, :3) and c = :2;
 
SELECT STATEMENT, GOAL = CHOOSE                     Cost=7   Cardinality=23    Bytes=414
 INLIST ITERATOR                                    
  TABLE ACCESS BY INDEX ROWID Object name=T_PEEKING3 Cost=7   Cardinality=23    Bytes=414
   INDEX RANGE SCAN Object name=T_PEEKING3_IDX1     Cost=1   Cardinality=23    

例:以下查询的集的势为round((2/10) * (1/13 + 1/1000) * 1000) = 16

select /*+index(a T_PEEKING3_IDX1)*/* from T_PEEKING3 a where  b in (:1, :2) and c > :2;
 
SELECT STATEMENT, GOAL = CHOOSE                     Cost=5   Cardinality=16    Bytes=288
 INLIST ITERATOR                                    
  TABLE ACCESS BY INDEX ROWID Object name=T_PEEKING3 Cost=5   Cardinality=16    Bytes=288
   INDEX RANGE SCAN Object name=T_PEEKING3_IDX1     Cost=1   Cardinality=16             

例:以下查询的集的势为round((2/10) * (3/13) * 1000) = 46

select /*+index(a T_PEEKING3_IDX1)*/* from T_PEEKING3 a where  b in (:1, :2) and c in (:1, :2, :3);
 
SELECT STATEMENT, GOAL = CHOOSE                     Cost=12  Cardinality=46    Bytes=828
 INLIST ITERATOR                                    
  TABLE ACCESS BY INDEX ROWID Object name=T_PEEKING3 Cost=12  Cardinality=46    Bytes=828
   INDEX RANGE SCAN Object name=T_PEEKING3_IDX1     Cost=1   Cardinality=46    

例:以下查询的集的势为round((1-1/10) * ((1- 1/13)^2) * 1000) = 767

select /*+index(a T_PEEKING3_IDX1)*/* from T_PEEKING3 a where  b <>:1  and c not in (:2, :3)
 
SELECT STATEMENT, GOAL = CHOOSE                     Cost=183 Cardinality=767   Bytes=13806
 TABLE ACCESS BY INDEX ROWID Object name=T_PEEKING3 Cost=183 Cardinality=767   Bytes=13806
  INDEX FULL SCAN Object name=T_PEEKING3_IDX1       Cost=3   Cardinality=767   

例:以下查询的集的势为round((1/20) * (1/13 + 1/1000) * 1000) = 4

select * from T_PEEKING3 where a not in (:1) and c > :2;
 
SELECT STATEMENT, GOAL = CHOOSE Cost=68     Cardinality=4    Bytes=732
 TABLE ACCESS FULL Object name=T_PEEKING3   Cost=2   Cardinality=4     Bytes=732        

全表扫描

对于全表扫描,如果没有查询条件时,

集的势因子 = 1

例:以下集的势为 1 * 1000 = 1000

select * from T_PEEKING3;
 
SELECT STATEMENT, GOAL = CHOOSE                     Cost=2   Cardinality=1000  Bytes=18000
 TABLE ACCESS FULL Object name=T_PEEKING3   Cost=2   Cardinality=1000  Bytes=18000

查询计划中集的势(Cardinality)的计算相关推荐

  1. mysql中len是什么意思_MySQL的查询计划中ken_len的含义

    本文首先介绍了MySQL的查询计划中ken_len的含义:然后介绍了key_len的计算方法:最后通过一个伪造的例子,来说明如何通过key_len来查看联合索引有多少列被使用. key_len的含义 ...

  2. mysql sql len_MySQL的查询计划中ken_len的值计算方法

    key_len的含义 在MySQL中,可以通过explain查看SQL语句所走的路径,如下所示: mysql> create table t(a int primary key, b int n ...

  3. 看懂SqlServer查询计划(转)

    转自:http://www.cnblogs.com/fish-li/archive/2011/06/06/2073626.html 对于SqlServer的优化来说,可能优化查询是很常见的事情.关于数 ...

  4. 看懂SQL Server的查询计划(绝对好文!)

    在园子看到一篇SQLServer关于查询计划的好文,激动啊,特转载.原文出自:http://www.cnblogs.com/fish-li/archive/2011/06/06/2073626.htm ...

  5. 看懂SqlServer查询计划

    原文:看懂SqlServer查询计划 对于SQL Server的优化来说,优化查询可能是很常见的事情.由于数据库的优化,本身也是一个涉及面比较的广的话题, 因此本文只谈优化查询时如何看懂SQL Ser ...

  6. sql server 缓存_了解SQL Server查询计划缓存

    sql server 缓存 Whenever a query is run for the first time in SQL Server, it is compiled and a query p ...

  7. 繁忙SQL Server上的查询计划

    Yesterday I came across a question on one of SQL forums, that I may rephrase like: 昨天我在一个SQL论坛上遇到一个问 ...

  8. sql server 缓存_搜索SQL Server查询计划缓存

    sql server 缓存 Whenever a query is executed in SQL Server, its execution plan, as well as some useful ...

  9. Plan Stitch:一种使用缝合物理计划解决查询计划性能退化问题的方法

    Part 1 论文背景 查询优化器选择了一个糟糕的执行计划而导致查询性能下降,是工作负载中的一个常见痛点.查询计划可能会因为各种原因而改变,比如创建删除索引.统计信息时,使用与上次不同的参数绑定重新编 ...

最新文章

  1. 每天一个linux命令(9):touch命令
  2. matlab功能块的作用,STEP7中功能块的使用属性说明
  3. oracle查询等于外的,Oracle 查询、更新基本操作
  4. 【转载】从头编写 asp.net core 2.0 web api 基础框架 (1)
  5. 【WebRTC---入门篇】(八)WebRTC核心之RTP Medio 媒体控制与数据统计
  6. CCIE-LAB-第七篇-IPV6 EIRGP+Passive
  7. 在新建FileInputStream时使用当前相对路径或者绝对路径作为参数的问题
  8. python+appium 自动化2--元素定位uiautomatorviewer
  9. oracle中查找某用户执行某张表的操作操作记录
  10. 本科毕设论文查重方法(重点介绍笔杆网站)
  11. CMMI3认证过程总结
  12. 电脑无损分区大小调整
  13. Redis 源码分析跳跃表(skiplist)
  14. 微信小程序怎么制作自己的程序呢?简单明了的步骤分享
  15. 中职计算机说课教法,2015教师资格证面试高中美术中职公共艺术美术篇说课稿 平面构成中的形象—活泼的点...
  16. Android自定义视频播放器(三)
  17. IBM Power小型机用液晶面板屏查看或设置HMC
  18. vue的生命周期函数
  19. 教大家微信里投票的怎么刷票及微信投票怎么免费刷票攻略
  20. python爬空气污染实时数据_python数据分析综合项目--空气质量指数分析

热门文章

  1. linux下安装微信wechat
  2. Centos7 Minimal 版安装后安装图形界面教程
  3. python2.7多线程的批量操作远程服务器
  4. java导入、导出Excel文件
  5. vue.js 三(数据交互)isomorphic-fetch
  6. 无向图强联通分量-洛谷 P2860 [USACO06JAN]冗余路径Redundant Paths
  7. 一个简单的pygame接金币游戏
  8. 进站公交车碾起积水溅上轿车两男子驾车撞伤公交司机
  9. Python django-restframework 前后端分离实现在线教育课程平台
  10. 什么是python编程例子_案例详解:优化Python编程的4个妙招