Я протестировал довольно много вариантов подзапросов в жизненном цикле создаваемой мной программы. 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
)
РЕДАКТИРОВАТЬ: С изменением требований (для большей фильтрации) многое изменилось, поэтому я решил обновить это. Конструкция, которую я пометил как 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].
Мое заключение:
- Когда исключение основано на одном поле, работают оба _16 _ / _ 17_. Один может быть лучше другого, в зависимости от используемых вами фильтров.
- Когда исключение основано на 2 или более полях и у вас нет соединения «многие ко многим» в основном запросе,
not exists ( select .. from table where id = a.id or id = b.id or... )
кажется лучшим.
- В тот момент, когда ваш критерий исключения реализует отношение «многие ко многим» в вашем основном запросе, я бы порекомендовал поискать оптимальный способ реализации нескольких подзапросов вместо этого (даже наличие подзапроса для каждой комбинации ключей и таблиц будет работать лучше, чем соединение многие-ко-многим с 1 хорошим подзапросом, что выглядит хорошо).
В любом случае, любое дополнительное понимание этого приветствуется.
EDIT2: хотя это немного не по теме, учитывая, что мой вопрос касался подзапросов, я решил, что опубликую обновление. Через год мне пришлось пересмотреть решение, над которым я работал, чтобы расширить его. Я узнал, что правильное исключение соединения работает. Я просто ужасно провалил это в первый раз.
select header~key
from headers left join items on headers~key = items~key
where items~key is null
person
Zero
schedule
14.05.2018