达梦数据库SQL优化——执⾏计划
今天主要介绍⼀下达梦数据库的执⾏计划,希望达到的效果是⽆论某个SQL是否的到优化的⽅法,我们起码可以将执⾏计划中的每⼀部分与原SQL对应起来。执⾏计划是优化的重中之重,这⾥我们主要讲解执⾏计划如何读,需要注意哪些地⽅,为优化做下⼀定的基础。
⼀、如何查看执⾏计划
⾸先,执⾏计划是由各类操作符组成的⼀颗树,也就是排序好的操作符的展现形式,从内到外依次执⾏
(看执⾏计划⼀般看MANAGER中执⾏计划⽂本的⽅式,这样看的更详尽⼀点,计划可以拷贝到⽂本编辑⼯具UE,NOTEPAD++中,这样缩进更为明显)
⼀般的执⾏计划格式为
OP1
OP2
OP3
OP4
OP5
OP6
OP7
OP8
缩进越多的越先执⾏,同样缩进的上⾯的先执⾏,下⾯的后执⾏,上下的优先级⾼于内外,对于上⾯这个简单的例⼦,⼤家可以⾃⼰写⼀个执⾏顺序
这⾥做⼀些空⾏,看写的执⾏顺序是否和后⾯列出的⼀致
这个例⼦的执⾏顺序为
OP3->OP4->OP2->OP7->OP8->OP6->OPT5->OP1
这⾥我们举⼀个现实的例⼦,我们拟定⼀个这样执⾏计划的SQL
CREATE TABLE TEST5(ID INT);
CREATE TABLE TEST6(ID INT);
CREATE TABLE TEST7(ID INT);
CREATE TABLE TEST8(ID INT);
insert into test5 values(3);
insert into test6 values(4);
insert into test7 select level%100from dual connect by level<10000;
insert into test8 select level%100from dual connect by level<10000;
SQL>explain select/*+no_use_cvt_var*/*from
(select test5.id from test5,test6 where test5.id = test6.id)
a,(select id from(select test7.id from test7,test8 where test7.id = test8.id)group by id) b where a.id = b.id;
这个例⼦(忽略/+no_use_cvt_var/)的执⾏计划,我们暂时不关注PRJT和NSET操作符,只看SQL的执⾏顺序
和前⾯的简单例⼦类似,执⾏顺序
6->7->5->12->13->11->9->3
换为⼈能理解的意思就是,⾸先执⾏TEST5和TEST6的HASH连接,然后执⾏TEST7,TEST8的HASH连接并将连接结果进⾏HASH分组,再将两个结果再次进⾏HASH连接得到最终结果集。
这个例⼦的SQL写法⽐较简单意义也是⾮常明确的,读懂SQL需要⼲什么可以把操作符顺序写下来不会很困难。同样的,只看到这个执⾏计划,我们需要能想出来这个SQL原本是什么样⼦。读懂SQL本
⾝是关键,执⾏计划更多的是起⼀个提⽰作⽤,侧⾯告诉⼤家SQL需要做什么事情
能正常读取执⾏计划描述的执⾏顺序后,我们关注下执⾏计划各个节点的详细信息,执⾏计划中所有操作符的后⾯都会有⼀个三元组,如:#CSCN2: [1, 9999, 4]
[1, 9999, 4]就是我们提到的这个三元组,3个数字分别表⽰该操作符的估算代价,该操作符的输出⾏数,该操作符涉及数据的⾏长。
#CSCN2: [1, 9999, 4] 表⽰的意义为,这是⼀个全表扫描操作,涉及的⾏数为9999,每场数据长度为4,整体代价估算为1。
我们将三元组中的第⼆项称为估算⾏数(card),在复杂查询中,估算⾏数对于执⾏计划以及SQL性能的影响很⼤。
⼆、统计信息
统计信息可以简单理解为将索引(包含原表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
SQL>explain select*from test10 where id1 =5;
可以看到CSCN涉及1W⾏数据,这个没有问题,但是过滤条件SLCT的CARD标注为250⾏(#SLCT2: [1, 250, 156]),这个和我们的预期是不⼀致的,因为不存在统计信息。
系统按10000 * 0.025直接给出250的结果。
如果存在多个等值条件呢?
----SEL21
----我们这⾥保障列与值类型相同 id2 varchar = ‘5’
SQL>explain select*from test10 where id1 =5and id2 ='5';
SLCT的CARD为6,约等于10000 * 0.025 * 0.025 = 6.25
可以简单推测出存在多个条件,且不存在统计信息的情况下,CARD是多个选择率的乘积乘以下层输出⾏数。
----我们再来看⼀般条件
----SEL22
SQL>explain select*from test10 where id1 >5;
SLCT输出CARD为500,和INI默认SEL_RATE_SINGLE参数0.05⼀致 10000 * 0.05 = 500
⼀般来说,除开等值条件外的所有过滤条件我们都认为是⼀般条件。
同样的,⼀般条件和等值条件的组合,没有统计信息的情况下,最终选择率依然是按乘积计算。
----SEL23
SQL>explain select*from test10 where id1 >5and id2 ='5';
SLCT CARD = 12 = 10000 * 0.05 * 0.025 = 12.5
现在我们收集统计信息,推荐收集统计信息的⽅式有两种
----收集单列统计信息数据库优化sql语句
STAT 100 ON 表(列)
----收集SQL语句涉及列的统计信息
CREATE VIEW VA AS SQL语句;
CALL SP_SQL_STAT_INIT(‘SELECT * FROM VA’)
SQL> stat 100on test10(id1);
操作已执⾏
已⽤时间: 26.350(毫秒).执⾏号:860.
SQL> stat 100on test10(id2);
操作已执⾏
收集完毕后,我们再看计划中的CARD值
SQL>explain select*from test10 where id1 =5;
已⽤时间: 0.689(毫秒). 执⾏号:0.
----单列估算准确,ID1只存在⼀个为5的⾏
SQL>explain select*from test10 where id2 ='5';
已⽤时间: 0.779(毫秒). 执⾏号:0.
----单列估算准确,CARD最⼩为1,ID2不存在为5的⾏
SQL>explain select*from test10 where id1 =5and id2 ='5';
----多列估算准备,不存在满⾜两个条件的⾏
SQL>explain select*from test10 where id1 >5;
----单列⼀般条件估算准确,9995个ID1 > 5
SQL>explain select*from test10 where id1 >5and id2 ='5';
----多列混合估算准确,不存在满⾜条件的⾏
由此可见,统计信息的收集可以⼤概率的修正对过滤⾏数的估算。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论