← Назад к вопросам

Какие знаешь свойства первичного ключа?

1.3 Junior🔥 161 комментариев
#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Свойства первичного ключа (Primary Key)

Первичный ключ (Primary Key) — это одна или несколько колонок, которые уникально идентифицируют каждую строку в таблице. Это фундаментальное понятие в проектировании баз данных.

Основные свойства первичного ключа

1. Уникальность (Uniqueness)

Если два значения первичного ключа одинаковые — СУБД не допустит дублирование строк.

CREATE TABLE users (
    user_id INT PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(100)
);

-- Попытка вставить дубликат
INSERT INTO users (user_id, name) VALUES (1, 'Alice');
INSERT INTO users (user_id, name) VALUES (1, 'Bob');  -- Ошибка: PRIMARY KEY нарушен

2. Уникальность — НЕ NULL значения

Первичный ключ никогда не может быть NULL. СУБД это гарантирует автоматически.

-- Попытка вставить NULL в первичный ключ
INSERT INTO users (user_id, name) VALUES (NULL, 'Charlie');  -- Ошибка

3. Неизменяемость (Immutability)

Да это могут изменить, но это плохая практика:

// Плохо: изменение первичного ключа
user.setId(999);  // Никогда так не делай!

// Хорошо: первичный ключ присваивается один раз при создании
User user = new User(1, "Alice");

Почему это проблематично:

  • Нарушаются отношения с другими таблицами (Foreign Keys)
  • Теряются исторические данные
  • Могут возникнуть конфликты индексов

4. Минимальность (Minimalism)

Первичный ключ должен содержать минимально необходимое количество колонок.

-- Плохо: много колонок в ключе
CREATE TABLE orders (
    user_id INT,
    order_date DATE,
    product_id INT,
    quantity INT,
    PRIMARY KEY (user_id, order_date, product_id)
);

-- Хорошо: отдельный ID
CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    user_id INT,
    order_date DATE,
    product_id INT,
    quantity INT,
    FOREIGN KEY (user_id) REFERENCES users(user_id)
);

5. Простота (Simplicity)

Первичный ключ обычно одна колонка, а не составной ключ.

-- Простой ключ (GOOD)
CREATE TABLE products (
    product_id INT PRIMARY KEY,
    name VARCHAR(100),
    price DECIMAL(10, 2)
);

-- Составной ключ (используется реже)
CREATE TABLE order_items (
    order_id INT,
    item_number INT,
    quantity INT,
    PRIMARY KEY (order_id, item_number)
);

6. Невыразительность (Not Expressive)

Первичный ключ не должен содержать смысловую нагрузку (в современном подходе).

-- Плохо: UUID содержит дату/время
CREATE TABLE users (
    user_id UUID DEFAULT uuid_generate_v1();  -- v1 содержит timestamp
);

-- Хорошо: просто UUID v4
CREATE TABLE users (
    user_id UUID DEFAULT uuid_generate_v4();  -- случайный
);

Типы первичных ключей

Natural Primary Key (Естественный ключ)

Основывается на реальных атрибутах сущности.

CREATE TABLE users (
    email VARCHAR(100) PRIMARY KEY,  -- Email уникален по природе
    name VARCHAR(100),
    phone VARCHAR(20) UNIQUE
);

Проблемы:

  • Email может измениться
  • Может быть очень длинным
  • Зависит от бизнес-логики

Surrogate Primary Key (Суррогатный ключ)

Искусственный числовой или UUID ключ, не имеющий смысла в бизнес-логике.

CREATE TABLE users (
    user_id INT PRIMARY KEY AUTO_INCREMENT,  -- Auto-increment
    email VARCHAR(100) UNIQUE,               -- Уникален, но не PK
    name VARCHAR(100)
);

-- Или UUID
CREATE TABLE users (
    user_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    email VARCHAR(100) UNIQUE,
    name VARCHAR(100)
);

Преимущества:

  • Никогда не изменится
  • Всегда уникален
  • Небольшой размер (для int/uuid)
  • Используется в современных приложениях

Свойства в контексте БД операций

Влияние на Performance

-- Первичный ключ автоматически индексируется
CREATE TABLE users (
    user_id INT PRIMARY KEY,  -- Автоматически создаётся индекс
    email VARCHAR(100)
);

-- Поиск по первичному ключу очень быстрый: O(1) или O(log n)
SELECT * FROM users WHERE user_id = 123;  -- Очень быстро!

Отношения с Foreign Keys

-- Первичный ключ в таблице users
CREATE TABLE users (
    user_id INT PRIMARY KEY
);

-- Используется как Foreign Key в таблице orders
CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    user_id INT NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(user_id)
);

Лучшие практики

1. Используй surrogate keys (суррогатные ключи)

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private UUID id;  // Лучше, чем email как PK
    
    @Column(unique = true, nullable = false)
    private String email;
}

2. Не изменяй первичный ключ

// Никогда:
user.setId(newId);  // ❌

// Правильно: create new and delete old
User newUser = new User(newId, user.getEmail());
repo.delete(user);
repo.save(newUser);

3. Используй индексы на Foreign Keys

CREATE INDEX idx_user_id ON orders(user_id);

4. Выбирай правильный тип ключа

  • Int/BigInt для небольших систем
  • UUID для распределённых систем, микросервисов
  • Snowflake ID для высоконагруженных систем

5. Документируй выбор ключа

/**
 * UUID используется для поддержки распределённого создания
 * без необходимости синхронизации с БД при создании объекта
 */
@Id
private UUID id;

Итог

Первичный ключ — это гарант уникальности и целостности данных. Выбор правильного типа ключа влияет на:

  • Производительность базы данных
  • Масштабируемость системы
  • Возможность распределённого создания сущностей
  • Простоту и понятность кода

Современный подход: UUID surrogate keys для большинства приложений.

Какие знаешь свойства первичного ключа? | PrepBro