Oracle数据库之所以强大,其中一个主要原因是因为他有极其完善的诊断方法,有问题不可怕,可怕的是无法根因分析、溯源、定位问题,就更谈不上从根本上解决问题了。
特别是性能优化部分,受到很多因素的影响,基于成本的优化器并不一定每次都能生成实际上最优的执行计划,为什么走了低效的索引、走了低效的连接方式等,Oracle数据库一般是可以借助10053 event进行判断的,以前一说起10053事件,马上联想到的就是Oracle数据库,但现在10053并不是Oracle独有的了,那么还有哪些数据库有10053事件呢?
我个人接触到的是达梦数据库,在进行SQL优化时,10053确实能帮助我更好的定位问题,其他数据库应该也会有类似的功能,只是名称、功能不同,下面简单看一下达梦数据库10053的使用方法:
1.检查并关闭monitor
达梦数据库开启monitor可能会对性能有影响,比如使用ET时需要提前开启monitor,但10053没有这个限制,可以在monitor关闭的情况下生成10053 trace,下面的实验是在monitor关闭情况下完成的:
SP_SET_PARA_VALUE(1,'ENABLE_MONITOR',0);
SP_SET_PARA_VALUE(1,'MONITOR_SQL_EXEC',0);
2.配置10053事件
语法和Oracle相同
alter session set events '10053 trace name context forever,level 1';
3.执行SQL
其中:t1表及测试数据生成方式见末尾。
SELECT ID,NAME FROM T1 WHERE NAME ='aaaaaaaaaa';
未选定行
4.关闭10053事件
alter session set events '10053 trace name context off';
5.查看10053 trace日志
查看路径
SQL> select PARA_NAME,PARA_VALUE from v$dm_ini where PARA_NAME like '%TRACE_PATH%';
行号 PARA_NAME PARA_VALUE
---------- ---------- ----------------------
1 TRACE_PATH db/dm8/data/cjc/trace
查看trace文件
dmdba@SATEST-DB-004:/db/dm8/data/cjc/trace$ls -lrth db/dm8/data/cjc/trace
-rw-r--r-- 1 dmdba dinstall 8.9K Mar 20 16:56 CJC_0320_1656_140272893910344.trc
分析trace
vi CJC_0320_1656_140272893910344.trc
1.列出达梦数据库版本信息
DM Database Server x64 V8[1-3-62-2023.12.23-213044-20067-ENT ], Dec 26 2023 20:08:39 built.
2.列出执行开始时间,执行的SQL文本,trace信息
*** 2024-03-20 16:56:57.127000000
*** Start trace 10053 event [level 1]
Current SQL Statement:
SELECT ID,NAME FROM T1 WHERE NAME ='aaaaaaaaaa';
3.列出数据库当前参数信息
*****************************
Parameters for this statement
*****************************
olap_flag = 2
mpp_flag = 0
enable_monitor = 0
......
4.优化前的执行计划
*** Plan before optimized:
project[0x7f93d40713e8] n_exp(3)
select[0x7f93d4070db8] (t1.name = 'aaaaaaaaaa')
base table[0x7f93d4070730] (t1, FULL SEARCH)
5.预估表基数
代价优化器依赖统计信息来评估选择。所谓选择率,是指一个数据集被应用一个条件谓词后,符合条件的记录数与原总记录数的比例。
当前表没有收集过统计信息,在没有统计信息的情况下,是按如下规则进行预估的:
列名=的谓词,选择率固定默认2.5%;
其他谓词,选择率固定默认5%;
所以预估出的match rows为10000(数据量)*2.5%=250,实际应该是0条。
***以上规则等信息参考达梦数据库官方文档***
>
*** stdesc 1: column = name, scan_type = EQU, key = ('aaaaaaaaaa')
stat_info(1128,1,'C')= {
#Valid = 'N',
#Type = '-',
#Card = 10000,
#NDV = 3333,
#Nulls = 100,
#LP = 9000,
#LVLS = 3,
#CLUF = 0,
#NK = 0,
#NS = 0}
---> st = 0.02500
>>>>> total: 10000, estimate match rows: 250, st: 0.02500; -- st_other: 1.000, n_stdesc: 1
6.比较单表访问路径所有执行计划的cost
---------------- single table access path probe for t1 ----------------
*** path 1: INDEX33555751 (FULL search), cost: 1.36455
*** path 2: i_t1_01 (FULL search), cost: 10.32495
*** path 3: i_t1_02 (EQU search), cost: 0.32250
分别比较了通过自动创建的聚簇索引INDEX33555751、id列索引i_t1_01、name列索引i_t1_02获取数据的cost,可以看到,走i_t1_02索引,cost最低。
7.选出cost最低的执行计划
>>> best access path: i_t1_02 (EQU search), cost: 0.32250
8.最后列出最优的执行计划
*** BEST PLAN FOR THIS STATEMENT ***
project[0x7f93d4085220] n_exp(3) (cost: 0.32250, rows: 250)
base table[0x7f93d4085d48] (t1, i_t1_02, EQU SEARCH) (cost: 0.32250, rows: 250)
-------------------------- END --------------------------
上述过程就是达梦数据库生成并分析10053 trace的一个简单案例,可以看到,和Oracle使用上非常类似。
下面看看如何手动生成SQL执行计划
1.explain
SQL> explain SELECT ID,NAME FROM T1 WHERE NAME ='aaaaaaaaaa';
1 #NSET2: [1, 250, 64]
2 #PRJT2: [1, 250, 64]; exp_num(3), is_atom(FALSE)
3 #BLKUP2: [1, 250, 64]; i_t1_02(t1)
4 #SSEK2: [1, 250, 64]; scan_type(ASC), i_t1_02(t1), scan_range['aaaaaaaaaa','aaaaaaaaaa']
2.autotrace
需要先开启monitor
SP_SET_PARA_VALUE(1,'ENABLE_MONITOR',1);
SP_SET_PARA_VALUE(1,'MONITOR_SQL_EXEC',1);
查看执行计划
set autotrace traceonly;
SELECT ID,NAME FROM T1 WHERE NAME ='aaaaaaaaaa';
1 #NSET2: [1, 250, 64]
2 #PRJT2: [1, 250, 64]; exp_num(3), is_atom(FALSE)
3 #BLKUP2: [1, 250, 64]; i_t1_02(t1)
4 #SSEK2: [1, 250, 64]; scan_type(ASC), i_t1_02(t1), scan_range['aaaaaaaaaa','aaaaaaaaaa']
Statistics
-----------------------------------------------------------------
0 data pages changed
0 undo pages changed
2 logical reads
0 physical reads
0 redo size
168 bytes sent to client
113 bytes received from client
1 roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
0 io wait time(ms)
0 exec time(ms)
最后,关闭monitor
SP_SET_PARA_VALUE(1,'ENABLE_MONITOR',0);
SP_SET_PARA_VALUE(1,'MONITOR_SQL_EXEC',0);
其中,上述案例中的t1表是按如下方式生成的:
create table cjc.t1 as select level as id,'xxxxx' as name from dual connect by level