Как ограничение CHECK может позволить оптимизатору исключить таблицу до её чтения?
Если оптимизатор видит достоверное ограничение CHECK и доказывает, что условие запроса ему противоречит, он может исключить таблицу или ветку UNION ALL из плана. Тогда чтение страниц и проверка строк не выполняются: результат формируется как заведомо пустой.
Это возможно только при доказуемом противоречии и корректно поддерживаемом ограничении. Проверка, реализованная лишь в приложении, такой оптимизации не даёт.
Реляционные оптимизаторы изначально стремились использовать не только индексы, но и логические свойства данных. Декларативные ограничения позволяют описать допустимое состояние таблицы один раз, чтобы оптимизатор мог применять это знание при преобразовании запроса.
Такой подход решает проблему лишнего чтения источников, в которых заведомо не может быть подходящих строк. Особенно заметен эффект у больших таблиц, архивных секций и объединений нескольких ограниченных по диапазонам источников.
Рассмотрим таблицу платежей, для которой гарантируется, что сумма неотрицательна. Запрос с условием отрицательной суммы не требует просмотра данных: множество возможных строк уже пусто.
Без доступного оптимизатору ограничения СУБД обычно обязана читать таблицу или индекс и проверять предикат для строк. Это создаёт лишний ввод-вывод, расход CPU и может привести к ненужным операциям соединения или агрегации.
Оптимизатор сопоставляет предикат запроса с ограничением. Если из ограничения следует, что предикат всегда ложен, источник помечается как недостижимый. В плане это может выглядеть как пустой результат, Constant Scan, Result с ложным условием или удалённая ветка объединения — конкретное представление зависит от СУБД.
Например, при ограничении amount >= 0 предикат amount < 0 несовместим с допустимыми значениями. Поэтому планировщик может вернуть пустой результат без обращения к таблице:
Важно, чтобы ограничение было проверенным и доверенным. Если в СУБД допускаются ограничения, добавленные без проверки существующих строк, либо ограничение помечено как недоверенное, оптимизатор не должен использовать его для безопасного исключения данных.
Оптимизация основана на доказательстве, а не на статистике. Поэтому свежесть статистики здесь не является главным условием, но сложное выражение, неявное преобразование типов или функция могут помешать распознать противоречие.
Нужно учитывать семантику NULL. В SQL проверка CHECK обычно запрещает только значения, для которых условие ложно; значение UNKNOWN из-за NULL может быть допустимым. Поэтому для строгого диапазонного вывода часто нужны одновременно NOT NULL и корректное ограничение.
Это не гарантирует ускорение любого запроса. Если противоречие нельзя доказать во время оптимизации, таблица останется в плане; кроме того, конкретная СУБД может применять такую оптимизацию только для определённых объектов, типов ограничений или режимов планирования.
В архивной системе данные были разделены на несколько таблиц по годам и объединены представлением через UNION ALL. У каждой таблицы имелось проверяемое ограничение на диапазон даты. Запрос за один месяц сначала рассматривал все таблицы, потому что диапазоны не были описаны декларативно.
Вариант без ограничений требовал чтения всех источников и фильтрации результата. Вариант с индексами по датам уменьшал стоимость чтения, но всё равно оставлял лишние обращения к таблицам; вариант с ручным выбором нужной таблицы усложнял приложение и создавал риск ошибок.
Выбрали проверенные CHECK-ограничения на диапазоны и сохранили единое представление. Оптимизатор смог исключить несовместимые ветки до чтения, поэтому запрос обращался только к релевантному источнику. Решение уменьшило ввод-вывод без дублирования логики маршрутизации в приложении, но потребовало контролировать корректность границ диапазонов при загрузке новых данных.
Нет. Оптимизатор должен суметь доказать противоречие между ограничением и предикатом в конкретном выражении. Различия типов, функции, неопределённая семантика NULL, преобразования и сложная логика могут сделать доказательство недоступным. Кроме того, СУБД может иметь ограничения на использование непроверенных или недоверенных ограничений.
Индекс помогает быстро находить потенциально подходящие строки, но обычно требует обращения к структуре индекса и иногда к таблице. CHECK задаёт логическое множество допустимых значений и может доказать, что источник вообще не нужно читать. Поэтому эти механизмы дополняют друг друга: ограничение может исключить источник целиком, а индекс — ускорить поиск внутри оставшегося источника.
Да, если запрос объединяет несколько источников с разными диапазонами или условиями. Ограничение может удалить заведомо несовместимые ветки, после чего оставшиеся таблицы обрабатываются обычным способом. Но само по себе ограничение не заменяет индекс: внутри оставшейся таблицы всё ещё может потребоваться сканирование, сортировка или соединение.