在 Oracle 12.1 上运行,我正在寻找计划中包含全表扫描的 SQL。
当我查看时:
select * from V$SQL_PLAN where sql_id = '89p47f9wnnwg9'
我返回了 21 行,其中一行的表访问权限为 FULL
但是,如果我为相同的 sql _id 调用此方法:
SELECT * FROM TABLE ( DBMS_XPLAN.DISPLAY_CURSOR ('89p47f9wnnwg9', 0, 'ALL'))
我得到的结果只有计划表中的 13 行,并且缺少 TABLE ACCESS FULL。
为什么会出现这种差异?
最佳答案
一个查询字符串(由 SQL_ID
表示)可以有多个不同的执行计划。所有内容都存储在 V$SQL_PLAN
中,并由不同的 CHILD_NUMBER
标识。
函数DBMS_XPLAN.DISPLAY_CURSOR有第二个参数,您可以在其中传递所需的 child_number。如果省略第二个参数,该函数将返回所有子游标,因此实际上您应该看到 V$SQL_PLAN 中的所有行(但在不同的执行计划中)。
要查看实际使用的是哪个子游标,您可以检查V$SESSION
列SQL_CHILD_NUMBER
。
12c 更新
这是对为什么 V$SQL_PLAN
的行数比 DBMS_XPLAN.DISPLAY_CURSOR
更多的问题的明显答案
在 Oracle 12c 版本之前,这是最有可能的一种。 12c介绍Adaptive Query Optimization
其中某些操作被优化器标记为不活动。这个选择可以通过执行引擎来切换。
此类计划可以通过操作STATISTICS COLLECTOR
来识别。 STATISTICS COLLECTOR 在执行时测试实际行数
如果它高于优化计算的拐点
,则切换计划。 (例如 - 嵌套循环对于几行工作正常,但是
对于大量来说,它是“悬挂”的;相反的散列连接适用于大量行,但对于少量行,它的开销很高。
拐点应该对应于这样的行数,其中成本估计相同)。
不幸的是,V$SQL_PLAN
中没有列标识非事件操作。
这个blog观察发现,可以使用元素 display_map
属性 @skp
OTHER_XML
列中提取此信息
<display_map>
<row op="1" dis="1" par="0" prt="0" dep="1" skp="0"/>
<row op="2" dis="2" par="1" prt="0" dep="2" skp="0"/>
<row op="3" dis="2" par="2" prt="0" dep="2" skp="1"/>
....
关于DBMS_XPLAN.DISPLAY_CURSOR 中的 SQL 计划差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48583868/