2013-12-17 5 views
0

Для очевидных причин производительности я хотел бы переписать существующий запрос Oracle SQL, который включает в себя коррелированные подзапросы, содержащие предложения «не в». Можно ли это сделать через внешние соединения или, возможно, какую-то другую технику?Переписывание коррелированного подзапроса с предложением «не в»

Вот код:

SELECT TRIM(et.event_id), TRIM(et.cancel_evt_id) 
FROM external_transactions et 
JOIN transaction_type tt 
    ON et.transaction_type_id = tt.transaction_type_id 
WHERE et.acct = 'ABCDEF' 
AND tt.transaction_type_class != 'XYZXYZ' 
AND 
(
    TRIM(et.event_id) NOT IN 
     (
     SELECT TRIM(t1.transaction_evt_id) 
     FROM transactions t1 
     WHERE t1.acct = et.acct 
     AND t1.asset_id = et.asset_id 
     AND t1.cancel_flag = 'N' 
     ) 
    OR TRIM(et.cancel_evt_id) NOT IN 
     (
     SELECT TRIM(t2.cancel_evt_id) 
     FROM transactions t2 
     WHERE t2.acct = et.acct 
     AND t2.asset_id = et.asset_id 
     AND t2.cancel_flag = 'Y' 
     ) 
) 
; 
+2

Каковы «очевидные причины»? Я подозреваю, что использование 'trim()' в идентификаторах делает запрос менее эффективным, чем в противном случае. –

+0

Опубликуйте свой план выполнения. –

+0

Выполнение левого соединения и применение WHERE IS NULL столбца, как правило, MUCH FASTER. Однако, что сказано ... каков фактический тип данных «et.event_id» и «t1.transaction_evt_id». Если числовое значение, TRIM() плохое, как указано в Gordon. – DRapp

ответ

0

Помимо комментариев, это если ваши колонки "ID" являются целыми числами на основе, а не строка, не пытайтесь конвертировать их.

Кроме того, чтобы помочь оптимизировать запрос, я бы обеспечить вам индексы

External_Transactions (acct, event_id, cancel_evt_id) 
Transaction_Type (transaction_type_id, transaction_type_class) 
Transactions (transaction_evt_id, acct, asset_id, cancel_flag) 
Transactions (cancel_evt_id, acct, asset_id, cancel_flag) 


SELECT 
     et.event_id, 
     et.cancel_evt_id 
    FROM 
     external_transactions et 
     JOIN transaction_type tt 
      ON et.transaction_type_id = tt.transaction_type_id 
      AND tt.transaction_type_class != 'XYZXYZ' 
     LEFT OUTER JOIN transactions t1 
      ON et.event_id = t1.transaction_evt_id 
      AND et.acct = t1.acct 
      AND et.asset_id = t1.asset_id 
      AND t1.cancel_flag = 'N' 
     LEFT OUTER JOIN transactions t2 
      ON et.cancel_evt_id = t2.cancel_evt_id 
      AND et.acct = t2.acct 
      AND et.asset_id = t2.asset_id 
      AND t2.cancel_flag = 'Y' 
    WHERE 
      et.acct = 'ABCDEF' 
     AND ( t1.transaction_evt_id IS NULL 
      OR t2.cancel_evt_id IS NULL) 

Вы могли бы даже принести пользу немного, если таблица транзакций имела индекс

Transactions (acct, asset_id, cancel_flag, transaction_evt_id, cancel_evt_id) 

и левый присоединиться был равен

SELECT 
     et.event_id, 
     et.cancel_evt_id 
    FROM 
     external_transactions et 
     JOIN transaction_type tt 
      ON et.transaction_type_id = tt.transaction_type_id 
      AND tt.transaction_type_class != 'XYZXYZ' 
     LEFT OUTER JOIN transactions t1 
      ON et.acct = t1.acct 
      AND et.asset_id = t1.asset_id 
      AND ( 
        ( t1.cancel_flag = 'N' 
        AND et.event_id = t1.transaction_evt_id) 
       OR 
        ( t1.cancel_flag = 'Y' 
        AND et.cancel_event_id = t1.cancel_evt_id) 
       ) 
    WHERE 
      et.acct = 'ABCDEF' 
     AND t1.transaction_evt_id IS NULL 

В обоих случаях индексы были бы индексами ПОКРЫТИЯ, так что это не было чтобы вернуться к страницам необработанных данных, чтобы подтвердить другие элементы записей

+0

DRapp, ваше первое решение, похоже, делает трюк. Сметная стоимость Oracle Explain Plan снижена с 315430 до 8715. Я все еще тестирую, чтобы гарантировать, что новый запрос вернет правильные результаты, но я еще не нашел условия тестирования, которые его еще не сломали. – ptc3

+0

И я также буду исследовать, является ли функция trim() логически необходимой, на основе предложений от нескольких людей. – ptc3

+0

@ ptc3, рад, что это сработало ... но просто интересно об улучшении производительности до/после времени ... – DRapp

0

Использование NOT EXISTS:

SELECT TRIM(et.event_id), TRIM(et.cancel_evt_id) 
FROM external_transactions et 
JOIN transaction_type tt 
    ON et.transaction_type_id = tt.transaction_type_id 
WHERE et.acct = 'ABCDEF' 
AND tt.transaction_type_class != 'XYZXYZ' 
AND NOT EXISTS 
     (
     SELECT 1 
     FROM transactions t1 
     WHERE t1.acct = et.acct 
     AND t1.asset_id = et.asset_id 
     AND (( t1.cancel_flag = 'N' 
       AND TRIM(et.event_id) = TRIM(t1.transaction_evt_id)) 
      OR 
       ( t1.cancel_flag = 'Y' 
       AND TRIM(et.cancel_evt_id) = TRIM(t1.cancel_evt_id)) 
      ) 
     ); 
+0

Корреляционные подзапросы, как правило, ужасны для производительности. – DRapp

+0

Действительно? [В чем разница между NOT EXISTS и NOT IN против LEFT JOIN WHERE NULL?] (Http://stackoverflow.com/questions/2246772/whats-the-difference-between-not-exists-vs-not-in -vs-left-join-where-is-null) или [вопрос относительно «Связанных подзапросов»] (http: //asktom.oracle.com/pls/asktom/f? p = 100: 11: 0 :::: P11_QUESTION_ID: 3167884300346662300) или [NOT IN vs. NOT EXISTS vs. LEFT JOIN/IS NULL: Oracle] (http://explainextended.com/2009/09/17/not-in-vs-not-exists-vs-left -join-is-null-oracle /) – MT0

+0

Not Exists и Not In будет предварительно запускать весь запрос и сначала возвращать все строки, а затем применяться для отдыха. Выполняя LEFT JOIN, двигатель просто устанавливает отношения между таблицами, и это либо их, либо нет (следовательно, поиск «ID» IS NULL). Указатели записи/указателя перемещаются одновременно с рассмотрением каждой записи из основной таблицы. Скажем, у вас есть 100 000 флажков отмены, но вам нужно только событие X, и у него 200 записей, из которых 18 отменены. Выдувание через 200, и все готово. – DRapp