我遇到了一个令人费解的情况。查询具有良好的执行计划。但是,当该查询被用作更大查询中的内部查询时,该计划发生了变化。我试图理解为什么会这样。
这是在 Oracle 11g 上。我的查询是:
SELECT * FROM YFS_SHIPMENT_H
WHERE SHIPMENT_KEY IN
(
SELECT DISTINCT SHIPMENT_KEY
FROM YFS_SHIPMENT_LINE_H
WHERE ORDER_HEADER_KEY = '20150113083918815889858'
OR ( ORDER_LINE_KEY IN ( '20150113084438815896336') )
);
可以看到,这里有一个内部查询,即:
SELECT DISTINCT SHIPMENT_KEY
FROM YFS_SHIPMENT_LINE_H
WHERE ORDER_HEADER_KEY = '20150113083918815889858'
OR ( ORDER_LINE_KEY IN ( '20150113084438815896336') )
当我只运行内部查询时,我得到的执行计划如下:
PLAN_TABLE_OUTPUT
========================================================================================================
SQL_ID 3v82m4j5tv1k3, child number 0
=====================================
SELECT DISTINCT SHIPMENT_KEY FROM YFS_SHIPMENT_LINE_H WHERE
ORDER_HEADER_KEY = '20150113083918815889858' OR ( ORDER_LINE_KEY IN (
'20150113084438815896336') )
Plan hash value: 3691773903
========================================================================================================
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
========================================================================================================
| 0 | SELECT STATEMENT | | | | 10 (100)| |
| 1 | HASH UNIQUE | | 7 | 525 | 10 (10)| 00:00:01 |
| 2 | CONCATENATION | | | | | |
| 3 | TABLE ACCESS BY INDEX ROWID| YFS_SHIPMENT_LINE_H | 1 | 75 | 4 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | YFS_SHIPMENT_LINE_H_I4 | 1 | | 3 (0)| 00:00:01 |
|* 5 | TABLE ACCESS BY INDEX ROWID| YFS_SHIPMENT_LINE_H | 6 | 450 | 5 (0)| 00:00:01 |
|* 6 | INDEX RANGE SCAN | YFS_SHIPMENT_LINE_H_I6 | 6 | | 3 (0)| 00:00:01 |
========================================================================================================
Predicate Information (identified by operation id):
===================================================
4 = access("ORDER_LINE_KEY"='20150113084438815896336')
5 = filter(LNNVL("ORDER_LINE_KEY"='20150113084438815896336'))
6 = access("ORDER_HEADER_KEY"='20150113083918815889858')
执行计划显示访问表 YFS_SHIPMENT_LINE_H 有两个索引 YFS_SHIPMENT_LINE_H_I4 和 YFS_SHIPMENT_LINE_H_I6;然后将结果连接起来。这个计划看起来不错,查询响应时间也很好。
但是当我运行完整的查询时,内部查询的访问路径会发生如下变化:
PLAN_TABLE_OUTPUT
=======================================================================================================
SQL_ID dk1bp8p9g3vzx, child number 0
=====================================
SELECT * FROM YFS_SHIPMENT_H WHERE SHIPMENT_KEY IN ( SELECT DISTINCT
SHIPMENT_KEY FROM YFS_SHIPMENT_LINE_H WHERE ORDER_HEADER_KEY =
'20150113083918815889858' OR ( ORDER_LINE_KEY IN (
'20150113084438815896336') ) )
Plan hash value: 3651083773
=======================================================================================================
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
=======================================================================================================
| 0 | SELECT STATEMENT | | | | 12593 (100)| |
| 1 | NESTED LOOPS | | | | | |
| 2 | NESTED LOOPS | | 7 | 6384 | 12593 (1)| 00:02:32 |
| 3 | SORT UNIQUE | | 7 | 525 | 12587 (1)| 00:02:32 |
|* 4 | INDEX FAST FULL SCAN | YFS_SHIPMENT_LINE_H_I2 | 7 | 525 | 12587 (1)| 00:02:32 |
|* 5 | INDEX UNIQUE SCAN | YFS_SHIPMENT_H_PK | 1 | | 1 (0)| 00:00:01 |
| 6 | TABLE ACCESS BY INDEX ROWID| YFS_SHIPMENT_H | 1 | 837 | 2 (0)| 00:00:01 |
=======================================================================================================
Predicate Information (identified by operation id):
===================================================
4 = filter(("ORDER_HEADER_KEY"='20150113083918815889858' OR
"ORDER_LINE_KEY"='20150113084438815896336'))
5 = access("SHIPMENT_KEY"="SHIPMENT_KEY")
请注意,现在正在使用不同的索引(YFS_SHIPMENT_LINE_H_I2) 访问 YFS_SHIPMENT_LINE_H。事实证明,这不是一个很好的索引,查询响应时间也会受到影响。
我的问题是:为什么内部查询执行计划在作为更大查询的一部分运行时会发生变化?一旦优化器找到了访问 YFS_SHIPMENT_LINE_H 的最佳方式,为什么即使它是更大查询的一部分,它也不会继续使用相同的执行计划?
注意:我不太关心什么是正确的访问路径或要使用的索引;因此这里没有给出表中的所有索引;和数据的基数。我担心的是单独执行而不是作为另一个查询的一部分执行的更改。
谢谢。
-- 段落