Ответ
Натуральный (естественный) ключ — это атрибут или набор атрибутов, имеющих бизнес-значение и уникально идентифицирующих запись (например, email, паспортные данные, артикул). Его использование сопряжено с серьезными проблемами:
Основные недостатки:
- Изменчивость (Mutability): Бизнес-данные могут меняться. Смена email пользователя потребует каскадного обновления всех внешних ключей в связанных таблицах, что сложно и рискованно.
- Низкая производительность: Строковые ключи (VARCHAR) обычно длиннее и сравниваются медленнее, чем целочисленные (BIGINT, INT). Это влияет на скорость JOIN, индексацию и размер индексов.
- Сложность обеспечения уникальности: В распределенных системах гарантировать глобальную уникальность значения (например, номера заказа) сложнее, чем использовать автоинкремент базы данных или UUID.
- Семантическая перегрузка: Ключ несет бизнес-смысл, который может со временем измениться или оказаться неверным.
- Сложность составных ключей: Если ключ состоит из нескольких полей, его использование в качестве внешнего ключа становится громоздким и неэффективным.
Рекомендуемый подход: Суррогатный ключ + уникальные ограничения.
-- НЕ РЕКОМЕНДУЕТСЯ: натуральный ключ
CREATE TABLE users (
email VARCHAR(255) PRIMARY KEY, -- Проблема: если email изменится
name VARCHAR(100)
);
-- РЕКОМЕНДУЕТСЯ: суррогатный ключ
CREATE TABLE users (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- Быстрый, неизменяемый
email VARCHAR(255) NOT NULL UNIQUE, -- Бизнес-уникальность через ограничение
name VARCHAR(100),
-- Дополнительный индекс для частых поисков по email
INDEX idx_email (email)
);
-- Внешние ключи ссылаются на стабильный `id`
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL, -- Ссылка на суррогатный ключ
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
Реализация в JPA/Hibernate:
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // Суррогатный ключ
private Long id;
@Column(unique = true, nullable = false) // Бизнес-уникальность
private String email;
// ... остальные поля
}
Исключения: Натуральные ключи иногда оправданы в справочных таблицах с небольшим, неизменным набором значений (например, country_code CHAR(2) PRIMARY KEY).