Я протестировал довольно много вариантов подзапросов в жизненном цикле программы, которую я создавал. NOT EXISTS
с проверкой нескольких полей (сокращенный пример ниже) для исключения на основе 2 ключей работает в некоторых случаях.
Производительность приемлема (время обработки около 5 секунд), хотя она заметно медленнее, чем тот же запрос, если исключить на основе 1 поля.
Select * from xxxx //xxxx is a result for a multiple table inner joins and 1 left join ( 1-* relation )
where NOT EXISTS (
select key from archive_table
where key = xxxx~key OR key = XXXX-foreign_key
)
EDIT:
С изменением требований (для дополнительной фильтрации) многое изменилось, поэтому я решил обновить это. Конструкция, которую я пометил как XXXX
в моем примере, содержала одиночное левое соединение (где отношение основной к вторичной таблице равно 1-*
), и оно появилось относительно быстро.
Здесь контекст становится полезным для понимания проблемы:
- Первоначальное требование: вытащить все
vendors
, без финансовых записей в 3
столы.
- Дополнительные требования: также исключать на основе альтернативных
payers
(1-*
отношение). Вот на чем основан пример выше.
- Дополнительные требования: также исключаются на основе альтернативного
payee
(*-*
отношения между payer
и payee
).
Соединение «многие ко многим» экспоненциально увеличило количество записей в конструкции, которую я назвал XXXX
, что, в свою очередь, приводит к ненужной работе. Например: один клиент с 3 payers
и 3 payees
произвел 9 строк с общим количеством проверяемых 27 полей (по 3 на строку), когда в действительности существует только 7 уникальных значений.
На этом этапе перемещение левосторонних таблиц из основного запроса в подзапросы и разбиение их дали значительно лучшую производительность.
чем любые более разумные альтернативы.
select * from lfa1 inner join lfb1
where
( lfa1~lifnr not in ( select lifnr from bsik where bsik~lifnr = lfa1~lifnr )
and lfa1~lifnr not in ( select wyt3~lifnr from wyt3 inner join t024e on wyt3~ekorg = t024e~ekorg and wyt3~lifnr <> wyt3~lifn2
inner join bsik on bsik~lifnr = wyt3~lifn2 where wyt3~lifnr = lfa1~lifnr and t024e~bukrs = lfb1~bukrs )
and lfa1~lifnr not in ( select lfza~lifnr from lfza inner join bsik on bsik~lifnr = lfza~empfk where lfza~lifnr = lfa1~lifnr )
)
and [3 more sets of sub queries like the 3 above, just checking different tables].
Мое заключение :
- Когда исключение основано на одном поле, оба
not in
/ not exits
работают. Один может быть лучше другого, в зависимости от используемых вами фильтров.
- Если исключение основано на 2 или более полях, и в основном запросе нет объединения «многие ко многим»,
not exists ( select .. from table where id = a.id or id = b.id or... )
представляется наилучшим.
- В тот момент, когда ваши критерии исключения реализуют отношение «многие ко многим» в вашем основном запросе, я бы порекомендовал вместо этого искать оптимальный способ реализации нескольких подзапросов (даже если иметь подзапрос для каждой комбинации таблицы ключей, работать лучше, чем соединение «многие ко многим» с одним хорошим подзапросом, что выглядит неплохо).
В любом случае, любое дополнительное понимание этого приветствуется.