Я столкнулся с загадочной ситуацией. У запроса был хороший план выполнения. Но когда этот запрос использовался как внутренний запрос в более крупном запросе, этот план изменился. Я пытаюсь понять, почему это может быть так.Выполнение плана внутреннего запроса отличается при запуске как часть более крупного запроса
Это было на 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 теперь доступен с различным индексом (YFS_SHIPMENT_LINE_H_I2). Как оказалось, это не очень хороший индекс, и время ответа на запрос страдает.
Мой вопрос: Почему внутренний план выполнения запроса изменяется, когда он выполняется как часть более крупного запроса? Как только оптимизатор разработал лучший способ доступа к YFS_SHIPMENT_LINE_H, почему бы ему не продолжать использовать тот же план выполнения, даже если он является частью более крупного запроса?
Примечание: Я не слишком обеспокоен тем, что будет правильным путем доступа или используемым индексом; и, следовательно, не дает здесь всех индексов на столе; и мощность данных. Моя озабоченность связана с изменением при выполнении отдельно по сравнению с частью другого запроса.
Спасибо.
- Параг
Вы правы, запрос может действительно быть сделано по-другому. Этот случай оказывается в коде, который я не могу изменить. ...... Кроме того, вы делаете хороший вывод о том, что вам не нужно использовать 'distinct' как часть предложения' in'. –