У меня проблемы с хранимой процедурой, которая для выполнения занимает около целой вечности. Она довольно большая, и я могу понять, что это займет некоторое время, но эта процедура продолжается почти 20 минут.
После некоторых отладок и исследований я заметил, что замена этой части пункта ГДЕ
;
((p_DrumNo IS NULL) OR T_ORDER.ORDER_ID IN (SELECT ORDER_ID FROM ORDERDELIVERY))
сделала огромную разницу. Так что процедура работает просто отлично до тех пор, пока p_DrumNo - NULL или я модифицирую вышесказанное, чтобы не проверять, не является ли p_DrumNo NULL;
(T_ORDER.ORDER_ID IN (SELECT ORDER_ID FROM ORDERDELIVERY))
Цель этого пункта WHERE
- отфильтровать результат, установленный на p_DrumNo, если он передан в Процедуру Хранения. Затем выражение WHERE
продолжается с дальнейшими условиями, но именно это условие останавливает запрос.
ORDERDELIVERY - это просто ~временная таблица, содержащая ORDER_IDs, связанные с параметром p_DrumNo.
Как эта простая NULL-проверка может вызвать такое большое влияние? Наверное, это связано с использованием OR
вместе с подзапросом, но я не понимаю, почему, так как сам подзапрос работает просто отлично.
Заранее спасибо!
UPDATE [2011-09-23 10:13]
Я разбил проблему на этот небольшой запрос, который показывает то же самое поведение;
Пример A
SQL запроса
SELECT * FROM T_ORDER WHERE
('290427' IS NULL OR ORDER_ID IN (SELECT ORDER_ID FROM T_ORDER WHERE ORDERNO LIKE '290427%') );
План выполнения
OPERATION OBJECT_NAME OPTIONS COST
------------------------------------------------------------
SELECT STATEMENT 97
FILTER
TABLE ACCESS T_ORDER FULL 95
TABLE ACCESS T_ORDER BY INDEX ROWID 2
INDEX PK_ORDER UNIQUE SCAN 1
Пример B
SQL запроса
SELECT * FROM T_ORDER WHERE
( ORDER_ID IN (SELECT ORDER_ID FROM T_ORDER WHERE ORDERNO LIKE '290427%') );
План выполнения
OPERATION OBJECT_NAME OPTIONS COST
------------------------------------------------------------
SELECT STATEMENT 4
NESTED LOOPS 4
TABLE ACCESS T_ORDER BY INDEX ROWID 3
INDEX IX_T_ORDER_ORDERNO RANGE SCAN 2
TABLE ACCESS T_ORDER BY INDEX ROWID 1
INDEX PK_ORDER UNIQUE SCAN 0
Как вы все видите, первый запрос (пример A) выполняет полное сканирование таблицы. Есть идеи, как этого избежать?