上篇DM7执行计划优化系列(一)——执行计划详解讲到执行计划中的估算行数受统计信息的影响。
这里简单介绍一下统计信息,统计信息可以简单理解为将索引(包含原表 ROWID 聚簇索引)的某一列进行统计分析,列出其最大最小值,存在多少个不同值,各个值存在多少个辅助信息。
对于没有统计信息的列,DM7 简单地按照一定比例进行概率过滤
涉及到的 INI 参数为
SEL_RATE_EQU 等值过滤选择率 默认为 0.025
SEL_RATE_SINGLE 一般条件选择率 默认为 0.05
例子:
CREATE TABLE TEST10(ID1 INT,ID2 VARCHAR,ID3 VARCHAR,ID4 VARCHAR);
--方便起见,我们插入1W行数据,ID1从1-10000, ID2 为 0a - 4a,ID3全为b,ID为1c - 10000c
INSERT INTO TEST10 SELECT LEVEL,LEVEL % 5 || 'A','B',LEVEL || 'C' FROM DUAL CONNECT BY LEVEL <= 10000;
--SEL20
EXPLAIN SELECT * FROM TEST10 WHERE ID1 = 5;
1 #NSET2: [1, 250, 156]
2 #PRJT2: [1, 250, 156]; exp_num(5), is_atom(FALSE)
3 #SLCT2: [1, 250, 156]; TEST10.ID1 = 5
4 #CSCN2: [1, 10000, 156]; INDEX33555457(TEST10)
可以看到 CSCN 涉及 1W 行数据,这个没有问题,但是过滤条件 SLCT 的 CARD 标注为 250 行(#SLCT2: [1, 250, 156]),这个和我们的预期是不一致的,因为不存在统计信息,系统按 10000 * 0.025 直接给出 250 的结果。
如果存在多个等值条件呢?
--SEL21
--我们这里保障列与值类型相同 ID2 VARCHAR = '5'
EXPLAIN SELECT * FROM TEST10 WHERE ID1 = 5 AND ID2 = '5';
1 #NSET2: [1, 6, 156]
2 #PRJT2: [1, 6, 156]; exp_num(5), is_atom(FALSE)
3 #SLCT2: [1, 6, 156]; (TEST10.ID1 = 5 AND TEST10.ID2 = '5')
4 #CSCN2: [1, 10000, 156]; INDEX33555457(TEST10)
SLCT 的 CARD 为6,约等于 10000 * 0.025 * 0.025 = 6.25
可以简单推测出存在多个条件,且不存在统计信息的情况下,CARD 是多个选择率的乘积乘以下层输出行数。
–我们再来看一般条件
--SEL22
EXPLAIN SELECT * FROM TEST10 WHERE ID1 > 5;
1 #NSET2: [1, 500, 156]
2 #PRJT2: [1, 500, 156]; exp_num(5), is_atom(FALSE)
3 #SLCT2: [1, 500, 156]; TEST10.ID1 > 5
4 #CSCN2: [1, 10000, 156]; INDEX33555457(TEST10)
SLCT 输出 CARD 为500,和 INI 默认 SEL_RATE_SINGLE 参数 0.05 一致(10000 * 0.05 = 500)
一般来说,除开等值条件外的所有过滤条件我们都认为是一般条件。
同样的,一般条件和等值条件的组合,在没有统计信息的情况下,最终选择率依然是按乘积计算。
--SEL23
EXPLAIN SELECT * FROM TEST10 WHERE ID1 > 5 AND ID2 = '5';
1 #NSET2: [1, 12, 156]
2 #PRJT2: [1, 12, 156]; exp_num(5), is_atom(FALSE)
3 #SLCT2: [1, 12, 156]; (TEST10.ID2 = '5' AND TEST10.ID1 > 5)
4 #CSCN2: [1, 10000, 156]; INDEX33555457(TEST10)
SLCT CARD = 12 = 10000 * 0.05 * 0.025 = 12.5
现在我们收集统计信息,推荐收集统计信息的方式有两种
收集单列统计信息
STAT 100 ON 表(列)
收集 SQL 语句涉及列的统计信息
CREATE VIEW VA AS SQL语句;
CALL SP_SQL_STAT_INIT(‘SELECT * FROM VA’)
具体到本文的例子中:
STAT 100 ON TEST10(ID1);
STAT 100 ON TEST10(ID2);
收集完毕后,我们再看计划中的CARD值
EXPLAIN SELECT * FROM TEST10 WHERE ID1 = 5;
1 #NSET2: [1, 1, 156]
2 #PRJT2: [1, 1, 156]; exp_num(5), is_atom(FALSE)
3 #SLCT2: [1, 1, 156]; TEST10.ID1 = 5
4 #CSCN2: [1, 10000, 156]; INDEX33555457(TEST10)
单列估算准确,ID1 只存在一个为 5 的行
EXPLAIN SELECT * FROM TEST10 WHERE ID2 = '5';
1 #NSET2: [1, 1, 156]
2 #PRJT2: [1, 1, 156]; exp_num(5), is_atom(FALSE)
3 #SLCT2: [1, 1, 156]; TEST10.ID2 = '5'
4 #CSCN2: [1, 10000, 156]; INDEX33555457(TEST10)
单列估算准确,CARD 最小为1,ID2 不存在为 5 的行
EXPLAIN SELECT * FROM TEST10 WHERE ID1 = 5 AND ID2 = '5';
1 #NSET2: [1, 1, 156]
2 #PRJT2: [1, 1, 156]; exp_num(5), is_atom(FALSE)
3 #SLCT2: [1, 1, 156]; (TEST10.ID1 = 5 AND TEST10.ID2 = '5')
4 #CSCN2: [1, 10000, 156]; INDEX33555457(TEST10)
多列估算准确,不存在满足两个条件的行
EXPLAIN SELECT * FROM TEST10 WHERE ID1 > 5;
1 #NSET2: [1, 9995, 156]
2 #PRJT2: [1, 9995, 156]; exp_num(5), is_atom(FALSE)
3 #SLCT2: [1, 9995, 156]; TEST10.ID1 > 5
4 #CSCN2: [1, 10000, 156]; INDEX33555457(TEST10)
单列一般条件估算准确,有 9995 个 ID1 > 5
EXPLAIN SELECT * FROM TEST10 WHERE ID1 > 5 AND ID2 = '5';
1 #NSET2: [1, 1, 156]
2 #PRJT2: [1, 1, 156]; exp_num(5), is_atom(FALSE)
3 #SLCT2: [1, 1, 156]; (TEST10.ID2 = '5' AND TEST10.ID1 > 5)
4 #CSCN2: [1, 10000, 156]; INDEX33555457(TEST10)
多列混合估算准确,不存在满足条件的行
由此可见,统计信息的收集可以大概率的修正对过滤行数的估算,但是并非所有情况都适用:我们知道,统计信息的收集是基于基础列做统计分析,如果列值上被套有函数,则统计信息会失效。
--SEL24
EXPLAIN SELECT * FROM TEST10 WHERE TRIM(ID1) > 5 ;
1 #NSET2: [1, 500, 156]
2 #PRJT2: [1, 500, 156]; exp_num(5), is_atom(FALSE)
3 #SLCT2: [1, 500, 156]; exp_cast(exp11) > 5
4 #CSCN2: [1, 10000, 156]; INDEX33555457(TEST10)
ID1 的值实际上没有变化,但是 SLCT CARD 不准确
另外需要小心的是隐式转换
-- SEL 25
EXPLAIN SELECT * FROM TEST10 WHERE ID2 > 5;
1 #NSET2: [1, 1, 156]
2 #PRJT2: [1, 1, 156]; exp_num(5), is_atom(FALSE)
3 #SLCT2: [1, 1, 156]; exp_cast(TEST10.ID2) > 5
4 #CSCN2: [1, 10000, 156]; INDEX33555457(TEST10)
这个和下面的等价
EXPLAIN SELECT * FROM TEST10 WHERE CAST(ID2 AS INT) > 5;
1 #NSET2: [1, 1, 156]
2 #PRJT2: [1, 1, 156]; exp_num(5), is_atom(FALSE)
3 #SLCT2: [1, 1, 156]; exp_cast(TEST10.ID2) > 5
4 #CSCN2: [1, 10000, 156]; INDEX33555457(TEST10)
不过目前的版本应该已经把简单的 CAST 的选择率修正了,这里的 SLCT CARD 都是正常。
文章
阅读量
获赞