Tom*_*mmi 5 oracle indexing performance oracle10g sql-execution-plan
我有一个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
Run Code Online (Sandbox Code Playgroud)
表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")
Run Code Online (Sandbox Code Playgroud)
因此,针对步骤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 111111)
7366 INDEX RANGE SCAN PRIMARY_KEY_INDEX_OF_TABLE_A (cr=49 pr=9 pw=0 time=810173 us)(object id 222222)
Run Code Online (Sandbox Code Playgroud)
所以现实中的基数是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
Run Code Online (Sandbox Code Playgroud)
这就是价值406的来源.就像亚当回答的那样,加入基数是join selectivity * filter cardinality (a) * filter cardinality (b)
,可以在上面跟踪报价的倒数第二行看到.
我不明白的是这Revised join sel
条线.1/12064是用于从表b中查找行的索引的选择性(表上的12064行,并且基于唯一ID进行选择).但那又怎么样?
基数似乎是通过将表b(4897354)的滤波器基数乘以表a(1/12064)的 选择性来计算的.为什么?当a - > b join不是基于a.id时,表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)
Run Code Online (Sandbox Code Playgroud)
但是,因为我们有一个多列连接,所以Join Selectivity不在表级别,它是每列上连接选择性的乘积(交集).假设游戏中没有空值:
Join Selectivity = Join Selectivity (key1) * Join Selectivity (key2)
Join Selectivity (key1) = ((5,000,000 - 0) / 5,000,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,000 - 0) / 5,000,000)
* ((10,000 - 0)) / 10,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)
Run Code Online (Sandbox Code Playgroud)
我们知道A上没有过滤器,因此表格过滤器基数是行数.我们从B中选择键值,因此表的过滤基数为1.
因此,估计估计加入基数的最佳情况是现在
Join Cardinality = 1/116 * 1/650 * 5,000,000 * 1
=~ 67
Run Code Online (Sandbox Code Playgroud)
向后工作可能更容易.根据我们所知,您的估计基数为406,导致加入选择性为406/5,000,000,即大约1/12315.这恰好是非常接近1 /(116 ^ 2),这是优化器中的一个健全性检查,以防止它在多列连接上找到过于激进的基数.
对于TL; DR人群:
归档时间: |
|
查看次数: |
7642 次 |
最近记录: |