Программирование SQLОсновы SQL и реляционная модельРазработчик серверных приложений

Зачем сохранять уникальность бизнес идентификатора после добавления суррогатного ключа?

Зачем сохранять уникальность бизнес-идентификатора после добавления суррогатного ключа?

Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Суррогатный ключ уникально идентифицирует строку технически, но не гарантирует уникальность сущности с точки зрения бизнеса. Поэтому бизнес-идентификатор обычно сохраняют под ограничением UNIQUE: это предотвращает появление двух строк, описывающих один и тот же объект.

Суррогатный ключ используют для ссылок и стабильной идентификации записи, а уникальность бизнес-атрибута — для защиты бизнес-правила.

Исторический контекст

Реляционная модель отделяет идентификацию кортежа от его содержательных атрибутов. На практике бизнес-идентификаторы могут изменяться, быть составными или иметь неудобный тип, поэтому для связей между таблицами часто вводят отдельный числовой или иной суррогатный ключ.

Однако появление технического ключа не отменяет ограничений предметной области. Если код клиента, номер договора или внешний идентификатор должны быть уникальными, это правило нужно выразить отдельно.

Постановка проблемы

Предположим, таблица имеет только суррогатный первичный ключ. Система может принять две строки с одинаковым бизнес-идентификатором, потому что их технические ключи различаются.

Это приводит к неоднозначному поиску, повторным начислениям, ошибкам синхронизации и дублированию данных при интеграции. Проверка уникальности только в приложении ненадёжна: пара конкурентных транзакций может одновременно пройти такую проверку.

Подробное решение

Суррогатный ключ отвечает на вопрос: «Как однозначно сослаться на эту строку?». Ограничение уникальности бизнес-атрибута отвечает на другой вопрос: «Могут ли две строки представлять один и тот же бизнес-объект?».

CREATE TABLE customer ( customer_id BIGINT PRIMARY KEY, external_code VARCHAR(50) NOT NULL UNIQUE, name VARCHAR(200) NOT NULL );

В этой схеме customer_id удобен для внешних ключей и не зависит от внешней системы. external_code защищён от дубликатов на уровне базы данных, поэтому конкурентные вставки не смогут создать двух клиентов с одним кодом.

Если бизнес-идентификатор состоит из нескольких атрибутов, уникальность задают для их комбинации. Если значение обязательно для идентификации, обычно нужны одновременно NOT NULL и UNIQUE: одно ограничение запрещает отсутствие значения, другое — повторение.

Важно отличать изменение значения от изменения идентичности. Бизнес-атрибут может измениться, поэтому использование его как единственного первичного ключа способно усложнить внешние ссылки и обновления. Суррогатный ключ сохраняет стабильные ссылки, но не должен использоваться как замена бизнес-ограничения.

Уникальность значений NULL имеет особенности SQL: сравнение с NULL не даёт обычного равенства, поэтому конкретное поведение допускаемых NULL и способы выразить условную уникальность зависят от СУБД. Для обязательного бизнес-идентификатора безопаснее явно задать NOT NULL.

Ситуация из практики

В системе клиентов внешний провайдер присваивает каждому клиенту код. Команда добавила внутренний customer_id и отказалась от уникальности внешнего кода, считая первичный ключ достаточной защитой.

Рассматривались два варианта. Проверка в коде была простой, но не защищала от гонки транзакций. Использование внешнего кода как первичного ключа сохраняло уникальность, но делало все внешние ссылки зависимыми от формата и возможных изменений идентификатора провайдера.

Выбрали суррогатный первичный ключ вместе с уникальным ограничением на внешний код. В результате связи остались стабильными, а база данных стала атомарно защищать правило «один код — один клиент».

Что кандидаты часто упускают

  1. Вопрос: Достаточно ли сделать бизнес-идентификатор индексированным?

    Ответ: Нет. Обычный индекс ускоряет поиск, но не запрещает одинаковые значения. Для защиты инварианта нужен уникальный индекс или, предпочтительнее на уровне модели, ограничение UNIQUE.

  2. Вопрос: Нужно ли сохранять уникальность бизнес-идентификатора, если все связи используют суррогатный ключ?

    Ответ: Да, если бизнес-правило требует уникальности. Внешние ключи обеспечивают корректность ссылок на строки, но не предотвращают создание нескольких строк с одинаковым содержательным идентификатором.

  3. Вопрос: Что произойдёт, если бизнес-идентификатор может быть NULL?

    Ответ: Ограничение UNIQUE обычно не запрещает несколько NULL, поскольку NULL не трактуется как обычное равное значение. Если отсутствие идентификатора недопустимо, добавляют NOT NULL; если уникальность нужна только для заполненных значений, применяют механизм условного уникального ограничения, поддерживаемый конкретной СУБД.