При каких условиях фильтр внешнего запроса можно безопасно протолкнуть внутрь производной таблицы с ограничением числа строк?
Фильтр нельзя безусловно проталкивать внутрь производной таблицы с LIMIT или другим ограничением числа строк: это может изменить набор строк, к которому применяется ограничение. Преобразование безопасно только тогда, когда фильтр не способен исключить ни одну строку, которая должна попасть в ограниченный результат, либо когда ограничение фактически не влияет на результат.
Проталкивание предикатов — классическое преобразование запросов, используемое оптимизаторами для уменьшения объёма данных как можно раньше. Чем меньше строк проходит через соединения, сортировки и агрегации, тем ниже затраты памяти и времени.
Однако ограничение числа строк — не просто фильтр. Оно выбирает конкретный префикс упорядоченного результата или некоторое допустимое подмножество строк, поэтому изменение порядка применения операций может изменить семантику запроса.
Рассмотрим запрос, который сначала выбирает двух самых высокооплачиваемых сотрудников, а затем оставляет только сотрудников отдела IT. Если сначала применить ограничение, отдел IT может быть представлен одной строкой или не представлен вовсе.
Если же сначала отфильтровать IT, а затем выбрать две самые высокие зарплаты, результат будет означать уже другую задачу — лучших сотрудников внутри IT. Ошибка особенно опасна в отчётах с пагинацией, рейтингами, top-N и выбором одной «лучшей» строки.
Логически производная таблица сначала формирует свой результат, включая ограничение числа строк, а внешний запрос затем фильтрует этот результат. Перестановка операций допустима только при сохранении результата для любых допустимых входных данных.
Минимальный пример:
Исходная логика сначала выбирает Алису и Бориса, поэтому результат содержит только Алису. При проталкивании фильтра внутрь сначала останутся Алиса и Светлана, а затем ограничение вернёт обе строки. Следовательно, преобразование изменило смысл запроса.
Безопасность возможна, например, если предикат гарантированно истинен для всех строк, которые могут попасть в результат ограничения, или если ограничение не сокращает фактический результат. Простое наличие ORDER BY не делает проталкивание безопасным: наоборот, оно часто делает различие явно наблюдаемым.
Оптимизатор может выполнять более сложные эквивалентные преобразования, например применять специальные алгоритмы top-N или использовать доказанные ограничения целостности. Но он не вправе просто переместить фильтр через LIMIT на основании того, что фильтрация обычно выгодна по производительности.
В API требовалось вернуть первые 20 опубликованных материалов по дате, а затем проверить доступ пользователя. Разработчик поместил проверку доступа снаружи производной таблицы, которая уже ограничивалась 20 строками. Для пользователя с ограниченным доступом это приводило к выдаче менее 20 материалов, хотя доступные материалы находились дальше в общем списке.
Рассматривались два варианта. Увеличить внутренний лимит можно было быстро, но это не гарантировало достаточное число доступных строк и ухудшало производительность. Оставить фильтр снаружи сохраняло исходную семантику, но не решало задачу наполнения страницы.
Выбрали вариант, при котором условие доступности стало частью отбора материалов до сортировки и ограничения. Это было не оптимизацией исходного запроса, а осознанным изменением постановки: требовались первые 20 доступных материалов, а не доступные строки среди первых 20 материалов. Результат стал стабильным, а число строк на странице соответствовало контракту API.
Нет. ORDER BY определяет, какие строки попадут под ограничение, но не устраняет зависимость от порядка операций. Если фильтр исключает строку из верхней части отсортированного списка, после его переноса следующая строка может занять её место.
Не обязательно. Например, условие по зарплате может исключить часть самых высокооплачиваемых сотрудников, после чего в top-N попадут следующие строки. Совпадение столбцов фильтра и сортировки само по себе не доказывает эквивалентность; нужно доказать, что порядок и состав ограниченного результата сохраняются.
Результат уже не определён конкретным порядком строк, но это не делает преобразование автоматически безопасным. СУБД может выбрать любые строки, и перенос фильтра изменит множество кандидатов, из которых выбираются эти строки. Отсутствие ORDER BY устраняет предсказуемость, но не устраняет семантическую границу, создаваемую ограничением.