加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Oracle解释计划估计索引范围扫描的基数不正确

发布时间:2020-12-12 16:26:24 所属栏目:百科 来源:网络整理
导读:我有一个Oracle 10.2.0.3数据库,以及这样的查询: select count(a.id) from LARGE_PARTITIONED_TABLE ajoin SMALL_NONPARTITIONED_TABLE b on a.key1 = b.key1 and a.key2 = b.key2where b.id = 1000 表LARGE_PARTITIONED_TABLE(a)有大约500万行,并由查询中
我有一个Oracle 10.2.0.3数据库,以及这样的查询:
select count(a.id) 
from LARGE_PARTITIONED_TABLE a
join SMALL_NONPARTITIONED_TABLE b on a.key1 = b.key1 and a.key2 = b.key2
where b.id = 1000

表LARGE_PARTITIONED_TABLE(a)有大约500万行,并由查询中不存在的列分区.表SMALL_NONPARTITIONED_TABLE(b)未分区,并保存大约10000行.

统计数据是最新的,并且表a的列key1和key2中有高度平衡的直方图.

表a具有主键和列key1,key2,key3,key4和key5上的全局非分区唯一索引.

查询解释计划显示以下结果:

---------------------------------------------------------------------------------------------------
| Id  | Operation          | Name                         | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                              |     1 |    31 |     4   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |                              |     1 |    31 |            |          |
|   2 |   NESTED LOOPS     |                              |   406 | 12586 |     4   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN| INDEX_ON_TABLE_B            |     1 |    19 |     2   (0)| 00:00:01 |
|*  4 |    INDEX RANGE SCAN| PRIMARY_KEY_INDEX_OF_TABLE_A |   406 |  4872 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("b"."id"=1000)
   4 - access("a"."key1"="b"."key1" and
              "a"."key2"="b"."key2")

因此,针对步骤4估计的行(基数)是406.

现在,tkprof跟踪显示以下内容:

Rows     Row Source Operation
-------  ---------------------------------------------------
      1  SORT AGGREGATE (cr=51 pr=9 pw=0 time=74674 us)
   7366   NESTED LOOPS  (cr=51 pr=9 pw=0 time=824941 us)
      1    INDEX RANGE SCAN INDEX_ON_TABLE_B (cr=2 pr=0 pw=0 time=36 us)(object id 222221)
   7366    INDEX RANGE SCAN PRIMARY_KEY_INDEX_OF_TABLE_A (cr=49 pr=9 pw=0 time=810173 us)(object id 222222)

所以现实中的基数是7366,而不是406!

我的问题是:在这种情况下,Oracle从哪里获得406的估计基数,以及如何提高其准确性,以便估计更符合查询执行期间的实际情况?

更新:这是我在查询上运行的10053跟踪的片段.

NL Join
  Outer table: Card: 1.00  Cost: 2.00  Resp: 2.00  Degree: 1  Bytes: 19
  Inner table: LARGE_PARTITIONED_TABLE  Alias: a
  ...
  Access Path: index (IndexOnly)
    Index: PRIMARY_KEY_INDEX_OF_TABLE_A
    resc_io: 2.00  resc_cpu: 27093
    ix_sel: 1.3263e-005  ix_sel_with_filters: 1.3263e-005
    NL Join (ordered): Cost: 4.00  Resp: 4.00  Degree: 1
      Cost_io: 4.00  Cost_cpu: 41536
      Resp_io: 4.00  Resp_cpu: 41536
  ****** trying bitmap/domain indexes ******
  Best NL cost: 4.00
          resc: 4.00 resc_io: 4.00 resc_cpu: 41536
          resp: 4.00 resp_io: 4.00 resp_cpu: 41536
Using concatenated index cardinality for table SMALL_NONPARTITIONED_TABLE
Revised join sel: 8.2891-e005 = 8.4475e-005 * (1/12064.00) * (1/8.4475e-005)
Join Card:  405.95 = outer (1.00) * inner (4897354.00) * sel (8.2891-e005)
Join Card - Rounded: 406 Computed: 405.95

这就是价值406的来源.像Adam回答的那样,加入基数是加入选择性*过滤基数(a)*过滤基数(b),可以在上面跟踪引用的倒数第二行看到.

我不明白的是Revised join sel line. 1/12064是用于从表b中查找行的索引的选择性(表上的12064行,并且基于唯一ID进行选择).但那又怎么样?

>基数似乎是通过计算得出的
乘以滤波器基数
表b(4897354)与
表a的选择性(1/12064).
为什么?什么
做选择性
表a与多少有关
预计将从中找到行
表b,当a – > b加入不是基于
援助?
>数字在哪里
8.4475e-005来自(它不会出现在整个其他地方
跟踪)?不是它影响了
输出,但我还是想知道.

我知道优化器可能在这里选择了正确的路径.但是基数仍然被误算 – 并且这可能对从该点开始选择的执行路径产生重大影响(就像我有IRL的情况一样 – 这个例子是对它的简化).

生成10053跟踪文件将有助于准确显示优化程序在估计基数和选择性方面所做的选择. Jonathan Lewis的精益求精的基于成本的Oracle基础知识是理解优化程序如何工作的优秀资源,以及我已经跨越8i到10.1的打印.

从那项工作:

Join Selectivity =   ((num_rows(t1) - num_nulls(t1.c1)) / num_rows(t1)) 
                   * ((num_rows(t2) - num_nulls(t2.c2)) / num_rows(t2))
                   / greater (num_distinct(t1.c1),num_distinct(t2.c2))

Join Cardinality =   Join Selectivity 
                   * filtered_cardinality (t1)
                   * filtered_cardinality (t2)

但是,因为我们有一个多列连接,所以Join Selectivity不在表级别,它是每列上连接选择性的乘积(交集).假设游戏中没有空值:

Join Selectivity = Join Selectivity (key1) * Join Selectivity (key2)

Join Selectivity (key1) =   ((5,000,000 - 0) / 5,000)
                          * ((10,000 - 0)) / 10,000)
                          / max (116,?)  -- distinct key1 values in B

                        = 1 / max(116,distinct_key1_values_in_B)

Join Selectivity (key2) =   ((5,000)
                          / max (650,?)  -- distinct key2 values in B

                        = 1 / max(650,distinct_key2_values in B)

Join Cardinality =  JS(key1) * JS(key2) 
                  * Filter_cardinality(a) * Filter_cardinality(b)

我们知道A上没有过滤器,因此表格过滤器基数是行数.我们从B中选择键值,因此表的过滤基数为1.

因此,估计估计加入基数的最佳情况是现在

Join Cardinality  = 1/116 * 1/650 * 5,000 * 1

                  =~ 67

向后工作可能更容易.根据我们所知,您的估计基数为406,导致加入选择性为406 / 5,即大约1/12315.这恰好是非常接近1 /(116 ^ 2),这是优化器中的一个健全性检查,以防止它在多列连接上找到过于激进的基数.

对于TL; DR人群:

>获取Jonathan Lewis的基于成本的Oracle基础知识.>获取10053跟踪您的行为无法理解的查询.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读