Согласен с моментом - "customer_id в таблице VIP'ов уникален (и вообще, должен быть FK и PK)". И действительно, тогда дистинкт не нужен в подзапросе для join. Для невхождения в данном примере это не будет играть роли, так как запрос всё равно переписывается в антисоединение. Для вхождения в случае с наличием PK на все запросы опять же таки переписываются в одинаковый Nested Loop и не имеют никакой разницы между друг другом. Так что хоть вы и правы в данном моменте, но по сути разницы это не составляет никакой.
Касательно конструкций intersect/except - действительно важное замечание. Я не рассматривал эти примеры лишь потому, что ни разу в своей практике не видел использования этих конструкций в реальном коде. На самом деле это устаревшие конструкции с заведомо проигрышными планами выполнения. Никто это не использует - и правильно делают. Даже на моих примерах:
Нахождение VIP`ов:
20-40 ms у других вариантов против 400+ ms у intersect
Скрытый текст
Нахождение "Кто хоть раз что-то купил":
20-30k ms у других вариантов против 100k+ у intersect:
Скрытый текст
Данные конструкции просто не выдерживают никакой критики и не рекомендуются к использованию никогда и никому.
Мне кажется вы не поняли общее направленность статьи. Я рассмотрел исключительно две типичные ситуации, которые я считаю самыми распространенными. Я не исключаю того, что есть запросы, для которых вышесказанное будет не актуально. Если вы приведете реальный подобный пример для нас всех это будет очень полезный опыт.
Операция дистинкта в случае WHERE IN и WHERE EXISTS не "обязана НЕ присутствовать", а "НЕ обязана присутствовать явно", потому что планировщик будет либо использовать полусоединение, которое подразумевает удаление дубликатов, либо самостоятельно вставит его в план при выборе других инструментов фильтрации (того же join, например). Как мы видим из плана выполнения со скрина, без использования явного дистинкта количество вернувшихся строк совпадает с ожиданиями (800 тыс.)
"тогда как в случае JOIN, наоборот, такая процедура обязательно должна выполняться" - разумеется должна, у нас выполняет соединение один ко многим, фильтровать дубликаты необходимо либо в подзапросе, либо на результирующем сете данных. Если этого не сделать, то на каждую запись из таблицы transactions будет своя запись в результирующем сете. Таким образом, вместо ожидаемых 800 тыс. строк мы получим все (или почти все) 100 млн. Это базовый функционал join.
Совершенно правильные замечания с точки зрения казуального юзера, взаимодействующего только с верхними слоями БД. Конечно в отношении "сервис - база данных" не должны участвовать хранимки. Однако не стоит забывать, что то, что вы видите от БД это лишь верхушка айсберга. Как известно на поверхности находится лишь 1/10 часть. Само формирование базы не представимо и полностью невозможно без использования хранимок. Если переводить в метафору - вы, в данном случае, владелец кредитного китайце в пробке, рассуждающий о том, что механическая коробка передач более не нужна и вообще морально устарела. А теперь представьте лицо профессионального гонщика (или Вин Дизеля), который бы это услышал. И вас понять можно, но и глупость, которую вы морозите, сложно оправдать. Не стоит обобщать весь мир АйТи под ваш опыт.
Согласен с моментом - "customer_id в таблице VIP'ов уникален (и вообще, должен быть FK и PK)". И действительно, тогда дистинкт не нужен в подзапросе для
join
. Для невхождения в данном примере это не будет играть роли, так как запрос всё равно переписывается в антисоединение. Для вхождения в случае с наличиемPK
на все запросы опять же таки переписываются в одинаковыйNested Loop
и не имеют никакой разницы между друг другом. Так что хоть вы и правы в данном моменте, но по сути разницы это не составляет никакой.Касательно конструкций intersect/except - действительно важное замечание. Я не рассматривал эти примеры лишь потому, что ни разу в своей практике не видел использования этих конструкций в реальном коде. На самом деле это устаревшие конструкции с заведомо проигрышными планами выполнения. Никто это не использует - и правильно делают. Даже на моих примерах:
Нахождение VIP`ов:
20-40 ms у других вариантов против 400+ ms у intersect
Скрытый текст
Нахождение "Кто хоть раз что-то купил":
20-30k ms у других вариантов против 100k+ у intersect:
Скрытый текст
Данные конструкции просто не выдерживают никакой критики и не рекомендуются к использованию никогда и никому.
Мне кажется вы не поняли общее направленность статьи. Я рассмотрел исключительно две типичные ситуации, которые я считаю самыми распространенными. Я не исключаю того, что есть запросы, для которых вышесказанное будет не актуально. Если вы приведете реальный подобный пример для нас всех это будет очень полезный опыт.
Операция дистинкта в случае WHERE IN и WHERE EXISTS не "обязана НЕ присутствовать", а "НЕ обязана присутствовать явно", потому что планировщик будет либо использовать полусоединение, которое подразумевает удаление дубликатов, либо самостоятельно вставит его в план при выборе других инструментов фильтрации (того же join, например). Как мы видим из плана выполнения со скрина, без использования явного дистинкта количество вернувшихся строк совпадает с ожиданиями (800 тыс.)
"тогда как в случае JOIN, наоборот, такая процедура обязательно должна выполняться" - разумеется должна, у нас выполняет соединение один ко многим, фильтровать дубликаты необходимо либо в подзапросе, либо на результирующем сете данных. Если этого не сделать, то на каждую запись из таблицы
transactions
будет своя запись в результирующем сете. Таким образом, вместо ожидаемых 800 тыс. строк мы получим все (или почти все) 100 млн. Это базовый функционал join.Совершенно правильные замечания с точки зрения казуального юзера, взаимодействующего только с верхними слоями БД. Конечно в отношении "сервис - база данных" не должны участвовать хранимки.
Однако не стоит забывать, что то, что вы видите от БД это лишь верхушка айсберга. Как известно на поверхности находится лишь 1/10 часть.
Само формирование базы не представимо и полностью невозможно без использования хранимок.
Если переводить в метафору - вы, в данном случае, владелец кредитного китайце в пробке, рассуждающий о том, что механическая коробка передач более не нужна и вообще морально устарела. А теперь представьте лицо профессионального гонщика (или Вин Дизеля), который бы это услышал. И вас понять можно, но и глупость, которую вы морозите, сложно оправдать. Не стоит обобщать весь мир АйТи под ваш опыт.
*Смайлик клоуна*