← Назад к вопросам
Может ли индекс быть по не уникальному полю?
1.0 Junior🔥 61 комментариев
#Базы данных и SQL
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Индексы по неуникальным полям в базах данных
Да, индекс может быть по неуникальному полю. Это один из самых распространённых типов индексов. Неуникальные индексы используют для ускорения поиска по часто используемым полям.
Типы индексов
1. Уникальный индекс (UNIQUE INDEX)
-- PostgreSQL / MySQL
CREATE UNIQUE INDEX idx_users_email ON users(email);
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE,
username VARCHAR(255)
);
INSERT INTO users (id, email) VALUES (1, 'john@example.com');
INSERT INTO users (id, email) VALUES (2, 'john@example.com'); -- ERROR!
2. Обычный индекс (NON-UNIQUE INDEX)
CREATE INDEX idx_users_status ON users(status);
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id INT,
status VARCHAR(50),
created_at TIMESTAMP
);
CREATE INDEX idx_orders_status ON orders(status);
CREATE INDEX idx_orders_user_id ON orders(user_id);
-- Дублирование разрешено
INSERT INTO orders (user_id, status) VALUES (1, 'pending');
INSERT INTO orders (user_id, status) VALUES (1, 'pending'); -- OK!
Практические примеры
Индекс по статусу заказа
-- Без индекса: полная таблица сканирование
EXPLAIN ANALYZE
SELECT * FROM orders WHERE status = 'pending';
-- С индексом: быстрый поиск
CREATE INDEX idx_orders_status ON orders(status);
SELECT * FROM orders WHERE status = 'pending';
Индекс по ID иностранного ключа
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id INT,
order_date TIMESTAMP,
total DECIMAL(10, 2)
);
-- Один пользователь может иметь много заказов
CREATE INDEX idx_orders_user_id ON orders(user_id);
SELECT * FROM orders WHERE user_id = 5;
Индекс по дате
CREATE TABLE logs (
id SERIAL PRIMARY KEY,
event_type VARCHAR(50),
created_at TIMESTAMP,
message TEXT
);
CREATE INDEX idx_logs_created_at ON logs(created_at);
SELECT * FROM logs
WHERE created_at >= '2024-01-01' AND created_at < '2024-01-02';
Составные индексы
CREATE TABLE sales (
id SERIAL PRIMARY KEY,
product_id INT,
region_id INT,
date DATE,
amount DECIMAL(10, 2)
);
-- По нескольким неуникальным полям
CREATE INDEX idx_sales_product_region
ON sales(product_id, region_id);
SELECT * FROM sales
WHERE product_id = 10 AND region_id = 5;
Индекс с фильтром
-- Только по активным заказам
CREATE INDEX idx_orders_status_active
ON orders(status)
WHERE status IN ('pending', 'processing');
SELECT * FROM orders WHERE status = 'pending';
Производительность индексов
-- Плохой индекс - низкая селективность (только 2 значения)
CREATE TABLE users (
id SERIAL PRIMARY KEY,
is_active BOOLEAN,
name VARCHAR(100)
);
CREATE INDEX idx_users_is_active ON users(is_active);
SELECT * FROM users WHERE is_active = true;
-- Может вернуть 500k строк, индекс может быть медленнее!
-- Лучше - составной индекс
CREATE INDEX idx_users_active_name ON users(is_active, name);
Индекс для JOIN операций
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
user_id INT,
total DECIMAL(10, 2)
);
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100)
);
-- Неуникальный индекс на foreign key
CREATE INDEX idx_orders_user_id ON orders(user_id);
SELECT u.name, SUM(o.total) as total_spent
FROM users u
JOIN orders o ON u.id = o.user_id
GROUP BY u.name;
Проверка эффективности индекса
-- Определить часто используемые WHERE условия
EXPLAIN ANALYZE
SELECT * FROM orders WHERE status = 'pending';
-- Проверить селективность (cardinality)
SELECT
status,
COUNT(*) as count,
ROUND(COUNT(*) * 100.0 / (SELECT COUNT(*) FROM orders), 2) as percentage
FROM orders
GROUP BY status
ORDER BY count DESC;
-- Если < 10% значений возвращается - хороший кандидат
-- Если > 50% значений - индекс может быть неэффективным
Затраты индексов
- Память: индекс занимает место на диске (10-30% размера таблицы)
- INSERT/UPDATE/DELETE: медленнее на 10-30%, так как нужно обновлять индекс
- SELECT: становятся быстрее на 10-100x
Вывод
- Индекс МОЖЕТ быть по неуникальному полю - это самый частый тип индекса
- Используй для часто используемых WHERE условий - ускоряет SELECT запросы
- Проверь селективность - индекс эффективен если вернёт менее 10% строк
- Составные индексы - для поиска по нескольким полям одновременно
- Для уникальности используй UNIQUE INDEX или PRIMARY KEY
- На foreign keys создавай индексы для ускорения JOIN операций
Неуникальные индексы - это основной инструмент оптимизации запросов в базах данных.