나는 당황스러운 상황에 직면했다. 쿼리에는 좋은 실행 계획이 있습니다. 그러나 그 쿼리가 더 큰 쿼리 내에서 내부 쿼리로 사용될 때 그 계획은 변경되었습니다. 왜 그렇게 될지 이해하려고 노력하고 있습니다.더 큰 쿼리의 일부로 실행될 때 내부 쿼리의 실행 계획이 달라짐
이것은 Oracle 11g에 있습니다. 내 쿼리는 그냥 내부 쿼리를 실행하면
SELECT DISTINCT SHIPMENT_KEY
FROM YFS_SHIPMENT_LINE_H
WHERE ORDER_HEADER_KEY = '20150113083918815889858'
OR (ORDER_LINE_KEY IN ( '20150113084438815896336'))
, 나는 실행 계획을 얻을 :
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_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 지금 다른 인덱스에 액세스하고 있습니다 (YFS_SHIPMENT_LINE_H_I2). 결과적으로 이것은 매우 좋은 지표는 아니며 쿼리 응답 시간도 겪습니다.
내 질문 : 더 큰 쿼리의 일부로 실행될 때 내부 쿼리 실행 계획이 변경되는 이유는 무엇입니까? 옵티마이 저가 YFS_SHIPMENT_LINE_H에 액세스하는 가장 좋은 방법을 찾았 으면 큰 쿼리의 일부일 때도 동일한 실행 계획을 계속 사용하지 않는 이유는 무엇입니까?
참고 : 올바른 액세스 경로 또는 사용할 인덱스가 무엇인지에 관해선별로 신경 쓰지 않습니다. 따라서 여기에있는 모든 색인을 테이블에 제공하지 마십시오. 및 데이터의 카디널리티. 내 관심사는 다른 쿼리의 일부로 대 별도로 실행될 때의 변경에 관한 것입니다.
감사합니다.
- Parag
당신이 옳다는 쿼리가 실제로 다른 방법으로 수행 할 수 있습니다. 이 코드는 내가 변경할 수없는 코드에서 발생합니다. ...... 또한,'in' 절의 일부로'distinct'를 사용할 필요가 없다는 것에 대해 좋은 지적을합니다. –