В запросе используют NATURAL JOIN; какое изменение схемы может незаметно изменить его результат?
Добавление в одну из таблиц нового столбца с именем, уже существующим в другой таблице, изменит условие NATURAL JOIN: этот столбец автоматически станет дополнительным ключом соединения. В результате могут исчезнуть строки или измениться набор совпадений без изменения текста запроса.
NATURAL JOIN появился как краткая форма соединения таблиц по всем одноимённым столбцам. Такой подход удобен, когда структура связанных таблиц стабильна и имена ключей согласованы.
Цена сокращённой записи — зависимость семантики запроса от схемы. Явное условие JOIN ... ON фиксирует используемые ключи в тексте запроса, а NATURAL JOIN неявно получает их из метаданных таблиц.
Предположим, таблицы сначала имеют общий столбец department_id. Соединение использует только его. Если позднее в таблицу сотрудников добавить столбец name, а в таблице подразделений он уже есть, соединение начнёт требовать совпадения одновременно по department_id и name.
Это может привести к неожиданному уменьшению результата, особенно если значения name имеют разное форматирование, локализацию или исторически не обязаны совпадать. Ошибка опасна тем, что запрос продолжает выполняться без синтаксических предупреждений.
Механизм NATURAL JOIN состоит из двух эффектов:
Минимальная иллюстрация изменения семантики:
После изменения схемы второй запрос фактически требует совпадения всех общих столбцов. Поэтому NATURAL JOIN плохо подходит для долговечных запросов, представлений, отчётов и публичных интерфейсов данных.
Надёжнее указывать условие явно: соединять таблицы по назначенным ключам через ON. Если требуется убрать дублирование ключевого столбца в результате, можно использовать USING, но только с явно названными столбцами; добавление другого одноимённого столбца тогда не изменит условие.
Следует учитывать диалект СУБД: поддержка и детали отображения результата могут различаться, но основная проблема — неявное использование всех совпадающих имён — сохраняется там, где NATURAL JOIN поддерживается.
В аналитическом отчёте использовался NATURAL JOIN между фактами продаж и справочником магазинов. Изначально общим столбцом был только store_id, поэтому отчёт показывал ожидаемые продажи.
Позднее в таблицу фактов добавили region для хранения региона операции. В справочнике магазинов уже существовал region, однако значения описывали разные правила классификации. Новый общий столбец автоматически попал в условие соединения, и часть продаж исчезла.
Рассматривались два варианта. Удаление нового столбца из одной таблицы устраняло симптом, но ограничивало модель данных и оставляло хрупкую зависимость. Замена соединения на явное JOIN ... ON store_id требовала небольшой правки, зато зафиксировала бизнес-смысл связи.
Выбран был второй вариант: запрос переписали с явным ключом, а для контроля добавили тест на количество строк отчёта. В результате схема смогла развиваться без скрытого изменения условий соединения.
1. Изменится ли NATURAL JOIN при добавлении одноимённого столбца только в одну таблицу?
Да, если имя нового столбца уже присутствует в другой таблице. Важен не факт добавления столбца вообще, а появление нового имени в пересечении наборов имён двух таблиц.
2. Эквивалентен ли NATURAL JOIN соединению по первичному и внешнему ключу?
Нет. Он не анализирует ограничения PRIMARY KEY или FOREIGN KEY и не выбирает «правильные» ключи по их назначению. Он использует исключительно совпадение имён столбцов, поэтому одноимённый технический, статусный или описательный столбец тоже может попасть в условие.
3. Почему явное перечисление столбцов предпочтительнее даже при полностью контролируемой схеме?
Потому что условие соединения становится видимым и проверяемым при чтении кода. Это упрощает ревью, предотвращает зависимость от будущих изменений схемы и помогает отличить обязательные ключи связи от случайно совпавших имён.