← Назад к вопросам
Нужно ли дополнительно создавать индекс при создании первичного ключа?
2.0 Middle🔥 151 комментариев
#Docker, Kubernetes и DevOps#JVM и управление памятью#ORM и Hibernate
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Индекс при создании первичного ключа
Ответ: Нет, не нужно. Первичный ключ автоматически создаёт индекс в большинстве баз данных.
Как работает PRIMARY KEY
PostgreSQL
-- Создаём таблицу с PRIMARY KEY
CREATE TABLE users (
id BIGINT PRIMARY KEY,
name VARCHAR(100)
);
-- PostgreSQL автоматически создаёт индекс!
-- Эквивалент:
CREATE UNIQUE INDEX users_pkey ON users(id);
Проверка:
-- Смотрим индексы
\d users;
-- Результат:
-- Table "public.users"
-- Column | Type | Collation | Nullable | Default
-- -------+------------------------+-----------+----------+---------
-- id | bigint | | not null |
-- name | character varying(100) | | |
-- Indexes:
-- "users_pkey" PRIMARY KEY, btree (id)
MySQL
CREATE TABLE users (
id BIGINT PRIMARY KEY,
name VARCHAR(100)
);
-- MySQL тоже создаёт индекс автоматически
-- Проверка:
SHOW INDEX FROM users;
-- Результаты:
-- Table | Non_unique | Key_name | Seq_in_index | Column_name | ...
-- users | 0 | PRIMARY | 1 | id | ...
Почему PRIMARY KEY включает индекс
PRIMARY KEY требует:
1. UNIQUE - значения не должны повторяться
2. NOT NULL - значение не может быть null
3. INDEXED - для быстрого поиска по id
Индекс нужен для:
- Быстрого поиска по PK:
SELECT * FROM users WHERE id = 123→ O(log n) - Проверки уникальности при INSERT
- Быстрого JOIN'а
Примеры в разных БД
PostgreSQL
-- ❌ ЛИШНЕЕ - индекс создастся автоматически
CREATE TABLE users (
id BIGINT PRIMARY KEY,
name VARCHAR(100)
);
CREATE INDEX users_id_idx ON users(id); -- Ненужный дубликат!
-- ✅ ПРАВИЛЬНО
CREATE TABLE users (
id BIGINT PRIMARY KEY,
name VARCHAR(100)
);
-- Индекс уже есть автоматически
MySQL
-- ПРАВИЛЬНО - PRIMARY KEY создаёт индекс
CREATE TABLE users (
id BIGINT PRIMARY KEY,
name VARCHAR(100)
);
-- Проверка
SHOW INDEX FROM users;
-- Видим индекс 'PRIMARY' на колонке id
Когда нужны дополнительные индексы
Дополнительные индексы нужны для других колонок:
CREATE TABLE users (
id BIGINT PRIMARY KEY, -- Индекс создан автоматически
email VARCHAR(100) UNIQUE, -- Индекс создан автоматически
name VARCHAR(100),
age INT,
created_at TIMESTAMP
);
-- ДОБАВЛЯЕМ индексы на часто используемые колонки
CREATE INDEX idx_users_name ON users(name); -- Часто ищем по имени
CREATE INDEX idx_users_age ON users(age); -- Часто фильтруем по возрасту
CREATE INDEX idx_users_created_at ON users(created_at); -- Сортируем по дате
PRIMARY KEY vs UNIQUE INDEX
-- PRIMARY KEY автоматически создаёт UNIQUE INDEX
CREATE TABLE users (
id BIGINT PRIMARY KEY -- UNIQUE + NOT NULL + индекс
);
-- Это эквивалентно:
CREATE TABLE users (
id BIGINT NOT NULL UNIQUE -- UNIQUE создаёт индекс
);
-- Визуально:
-- PRIMARY KEY = UNIQUE INDEX + NOT NULL constraint
В Java/JPA
// В Hibernate/JPA автоматически создаются индексы
@Entity
@Table(name = "users")
public class User {
@Id // PRIMARY KEY - индекс создан в БД автоматически
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true) // Создаст UNIQUE INDEX автоматически
private String email;
@Column
private String name;
}
// При создании схемы Hibernate:
// CREATE TABLE users (
// id BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
// email VARCHAR(255) UNIQUE,
// name VARCHAR(255)
// );
//
// Индексы создаст автоматически!
Миграции (Goose SQL)
-- ✅ ПРАВИЛЬНО - PRIMARY KEY создаст индекс
CREATE TABLE users (
id BIGINT PRIMARY KEY,
email VARCHAR(100) NOT NULL UNIQUE,
name VARCHAR(100) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE
);
-- Если хочешь добавить индекс на другую колонку:
CREATE INDEX idx_users_email ON users(email); -- Хотя UNIQUE уже имеет индекс
CREATE INDEX idx_users_name ON users(name);
CREATE INDEX idx_users_created_at ON users(created_at);
Миграция: до и после
-- Миграция 1: создаём таблицу
-- file: 0001_create_users.sql
CREATE TABLE users (
id BIGINT PRIMARY KEY, -- Индекс создан автоматически!
email VARCHAR(100) UNIQUE, -- Индекс создан автоматически!
name VARCHAR(100),
created_at TIMESTAMP
);
-- Миграция 2: добавляем индексы на часто используемые колонки
-- file: 0002_add_indexes.sql
CREATE INDEX idx_users_name ON users(name);
CREATE INDEX idx_users_created_at ON users(created_at);
-- Готово! Теперь все индексы на месте
Проверка производительности
С PRIMARY KEY (индекс есть):
SELECT * FROM users WHERE id = 123; -- ⚡ Быстро (индекс)
-- Execution time: 0.001ms
Без индекса на другой колонке:
SELECT * FROM users WHERE name = 'John'; -- 🐌 Медленно (полная таблица)
-- Execution time: 45ms (на таблице из 1 млн строк)
С индексом на name:
CREATE INDEX idx_users_name ON users(name);
SELECT * FROM users WHERE name = 'John'; -- ⚡ Быстро
-- Execution time: 0.5ms
Типичная схема таблицы
CREATE TABLE orders (
-- Primary Key - АВТОМАТИЧЕСКИЙ индекс
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
-- Foreign Key - рекомендуется индекс
user_id BIGINT NOT NULL,
-- Уникальное поле - АВТОМАТИЧЕСКИЙ индекс
order_number VARCHAR(20) UNIQUE NOT NULL,
-- Обычные поля - БЕЗ индексов (добавляем по необходимости)
total_amount DECIMAL(10, 2),
status VARCHAR(20),
created_at TIMESTAMP WITH TIME ZONE,
FOREIGN KEY(user_id) REFERENCES users(id)
);
-- ДОПОЛНИТЕЛЬНЫЕ индексы на часто используемые поля
CREATE INDEX idx_orders_user_id ON orders(user_id); -- Для JOIN'ов
CREATE INDEX idx_orders_status ON orders(status); -- Для фильтрации
CREATE INDEX idx_orders_created_at ON orders(created_at); -- Для сортировки
Контрольный список
Индексы создаются АВТОМАТИЧЕСКИ:
- ✅ PRIMARY KEY
- ✅ UNIQUE constraint
- ✅ FOREIGN KEY (в большинстве БД)
Индексы нужно создавать ВРУЧНУЮ:
- ❌ Колонки в WHERE (но не PK/UNIQUE)
- ❌ Колонки в ORDER BY
- ❌ Колонки в JOIN
- ❌ Колонки в GROUP BY
Вывод
Не нужно дополнительно создавать индекс при PRIMARY KEY. Он создаётся автоматически.
Нужно создавать индексы на:
- Колонки в WHERE условиях (если не PK)
- Kolonки в JOIN'ах
- Kolonки в ORDER BY
Правило большого пальца:
- Если ты часто ищешь по колонке → создай индекс
- Если ты редко ищешь → не создавай
- Следи за production метриками (slow queries log)