如何诊断SQL数据?

当一个SQL出现性能问题时,可以使用SQL_TRACE 或者 10046事件来跟踪SQL,通过生成的trace来了解SQL的执行过程。我们在查看一条SQL的执行计划的时候,只能看到CBO 最终告诉我们的执行计划结果,但是不知道CBO 是根据什么来做的。如果遇到了执行计划异常,可以借助Oracle 10053事件进行跟踪。10053事件是oracle提供的用于跟踪sql语句成本计算的内部事件,它能记载CBO模式下oracle优化器如何计算sql成本,生成相应的执行计划。

通过session级别跟踪:

ALTER SESSION SET EVENTS='10053 trace name context forever, level 1';

或ALTER SESSION SET EVENTS='10053 trace name context forever, level 2';

执行相关sql

explain plan for select count(*) from obj$;

ALTER SESSION SET EVENTS '10053 trace name context off';

对特定session启用跟踪:

通过调用 DBMS_SYSTEM. SET_EV包实现

PROCEDURE SET_EV

Argument Name Type In/Out Default?

------------------------------ ----------------------- ------ --------

SI BINARY_INTEGER IN

SE BINARY_INTEGER IN

EV BINARY_INTEGER IN

LE BINARY_INTEGER IN

NM VARCHAR2 IN

查询v$sessiowww.pizei.comn 视图获取进程信息

SQL> select sid,serial#,username from v$session where username is not null;

SID SERIAL# USERNAME


125 25 SYS

执行跟踪

exec dbms_system.SET_EV(125,25,10053,1,'');

结束跟踪

exec dbms_system.SET_EV(125,25,10053,0,'');

查询系统对应session trace文件

select value from v$diag_info where name = 'Default Trace File';

经过开发人员确认该sql在测试库(LINUX+ 12.2.0.1 单机环境)执行只需要几秒即可(数据量相差不大)完成,其中bs_loan_card_addition、bs_loan_card、bs_loan_contract_addition三张表的数据量都在200万行左右。

获取到生产环境该sql执行计划如下:

测试环境该sql执行计划如下:

首先怀疑统计信息不准确导致CBO在页游访问BS_LOAN_CARD表的时候选择错误,本应该选择BS_LOAN_CARD_I3索引(因为CUSTOMER_NO"='1000193229’的选择性很好)而这也是开发设计这个索引的原因。但结果是选择了BS_LOAN_CARD_I0索引(对应的是BS_LOAN_CARD.LOAN_CARD_NO,该列唯一的),而过滤条件根本没有这个列,他只是作为关联条件与bs_loan_card_addition表进行连接。

因此首先检查统计信息,意外发现BS_LOAN_CARD.LOAN_CARD_NO,列上居然存在一个HYBIRD类型的直方图,理论上来说该值的唯一性非常好,不应该收集直方图,因此直接删除了该列上的直方图,再次检查发现执行计划仍未改变。

尝试使用10053对该SQL执行计划的产生过程进行跟踪,发现如下信息:

而且结合执行计划

这个执行计划简单理解来说就是首先对BS_LOAN_CARD_ADDITION进行全表扫描,然后在这个所得的结果集里面每一行的LOAN_CARD_NO列拿出来到BS_LOAN_CARD里面匹配,这就是第6部里面出现了一个"B"."LOAN_CARD_NO"=:B1原因,而这个就是oracle改写后的结果。而从其选择对BS_LOAN_CARD_ADDITION进行全表扫描就不可避免的导致了效率会很低。而且其后的rows 估算为2444K,这个是贴合实际的,所以之前的删除直方图不会有结果。而测试上的改写结果明显跟这个不一样,排除统计信息的影响,那么就开始怀疑cbo内部的算法选择问题,再结合那个可疑 的 “CBQT bypassed forquery block UPD$1 (#0): Disabled by parameter. ”提示,怀疑优化器参数在两个环境中有区别,

一:_optimizer_cost_based_transformation设为linear(默认值),其有如下值:

"exhaustive", "iterative","linear", "on", "off"。

本例中该参数就是默认值,该参数可控制是否允许CBO进行改写

二:_optimizer_squ_bottomup 参数值为true(默认值).

而生产环境中恰好相反为false,所以生产的trace中会有Disabled by parameter 字眼

_optimizer_squ_bottomup enables unnesting of subquery in a bottom-upmanner;

该参数默认为true,即开启子查询自底向上的展开功能(也就是类似unnest hint的功能),unnest称之为对子查询展开,顾名思义,就是不让子查询孤单地嵌套(nest)在里面。

上一篇:SQLite使用教程5 分离数据库


下一篇:Python爬虫和数据可视化