Какое условие не рекомендует использовать индексы?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Когда не рекомендуется использовать индексы
Индексы — мощный инструмент оптимизации запросов в базах данных, но они имеют свою цену. Существует ряд условий, когда создание индексов неэффективно или даже вредно.
1. Столбцы с низкой селективностью (cardinality)
Селективность — это отношение количества уникальных значений к общему количеству строк.
Если столбец содержит мало уникальных значений, индекс не даёт преимущества:
-- Таблица пользователей с 1 млн строк
CREATE TABLE users (
id BIGINT PRIMARY KEY,
email VARCHAR(255),
is_active BOOLEAN -- только 2 уникальных значения!
);
-- Плохой индекс — низкая селективность
CREATE INDEX idx_is_active ON users(is_active);
Почему это плохо? Если is_active = true встречается в 900k строк, индекс всё равно придётся считывать 900k строк, не экономя ничего. Без индекса полная таблица также даст правильный результат примерно с одинаковой стоимостью.
Пример с селективностью:
-- Хорошо — высокая селективность (1 млн уникальных email)
CREATE INDEX idx_email ON users(email);
-- Плохо — низкая селективность (2-3 уникальных статуса)
CREATE INDEX idx_status ON users(status);
2. Таблицы с малым количеством строк
Для маленьких таблиц (несколько тысяч строк) полный скан таблицы часто быстрее, чем использование индекса:
CREATE TABLE roles (id INT, name VARCHAR(100));
-- Всего 10 строк
-- Индекс здесь неполезен
CREATE INDEX idx_name ON roles(name);
-- Полный скан таблицы (10 строк) быстрее обращения к индексу
SELECT * FROM roles WHERE name = 'admin';
Почему? Затраты на поиск в индексе и получение данных из таблицы больше, чем просто прочитать всю маленькую таблицу.
3. Столбцы с частыми NULL значениями
Основные СУБД обрабатывают NULL проблематично в индексах:
-- PostgreSQL исключает NULL из индекса
CREATE INDEX idx_phone ON users(phone);
-- Запрос WHERE phone IS NULL **не использует индекс**
SELECT * FROM users WHERE phone IS NULL;
Если в столбце много NULL значений, индекс становится неполным и не помогает в типичных запросах.
4. Столбцы, часто обновляемые
Каждое обновление индексированного столбца требует обновления индекса, что имеет затраты:
CREATE TABLE server_metrics (
id BIGINT PRIMARY KEY,
cpu_usage INT, -- обновляется каждую секунду
timestamp TIMESTAMP
);
-- Плохой индекс
CREATE INDEX idx_cpu_usage ON server_metrics(cpu_usage);
-- Каждое обновление 1 млн метрик требует обновления индекса
UPDATE server_metrics SET cpu_usage = ? WHERE id = ?;
Пересчёт индекса может стоить дороже, чем выигрыш в SELECT запросах.
5. Столбцы с вычисляемыми функциями
Если запрос использует функцию на столбце, обычный индекс не поможет:
CREATE INDEX idx_name ON users(name); -- обычный индекс
-- Этот запрос **не использует индекс**!
SELECT * FROM users WHERE UPPER(name) = 'ALICE';
Потребуется функциональный индекс:
-- PostgreSQL
CREATE INDEX idx_upper_name ON users(UPPER(name));
-- Теперь запрос использует индекс
SELECT * FROM users WHERE UPPER(name) = 'ALICE';
6. Широкие индексы (слишком много колонок)
Индекс по 5-6 столбцам занимает много памяти и может быть медленнее полного скана:
-- Плохо — слишком много колонок
CREATE INDEX idx_wide ON users(email, first_name, last_name,
phone, address, city);
-- Индекс может быть больше, чем сама таблица
-- и медленнее, чем полный скан
7. Редко используемые столбцы в фильтрах
Если столбец фильтруется в очень редких запросах, индекс — пустая трата памяти:
-- Таблица логов с 100 млн строк
CREATE TABLE audit_logs (
id BIGINT PRIMARY KEY,
user_id BIGINT,
action VARCHAR(100),
ip_address VARCHAR(15) -- используется в 0.1% запросов
);
-- Индекс здесь ненужен
CREATE INDEX idx_ip ON audit_logs(ip_address);
Стоимость хранения больше, чем выигрыш в 0.1% запросов.
8. Столбцы с высокой частотой полнотекстового поиска
Для полнотекстового поиска нужны специализированные индексы, не обычные B-Tree:
-- Плохо — обычный индекс не поможет
CREATE INDEX idx_content ON articles(content);
-- Правильно — полнотекстовый индекс
CREATE FULLTEXT INDEX idx_content ON articles(content);
SELECT * FROM articles WHERE MATCH(content) AGAINST('database');
Практические рекомендации
Создавай индексы только если:
- Высокая селективность (>5% уникальных значений)
- Таблица достаточно большая (>100k строк) и часто используется в фильтрах
- Затраты на обновление индекса < выигрыш в SELECT запросах
- Столбец часто используется в WHERE, JOIN, ORDER BY запросах
- Память доступна для хранения индекса
Мониторинг неиспользуемых индексов
Проверь, какие индексы не приносят пользу:
-- PostgreSQL
SELECT schemaname, tablename, indexname, idx_scan
FROM pg_stat_user_indexes
WHERE idx_scan = 0
ORDER BY pg_relation_size(indexrelid) DESC;
-- MySQL
SELECT object_schema, object_name, count_read, count_write
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE count_read = 0
ORDER BY count_write DESC;
Удали неиспользуемые индексы — они только замедляют обновления и занимают память.
Вывод
Индексы — это инструмент, требующий осознанного применения. Не добавляй индекс просто так. Профилируй запросы, анализируй план выполнения и создавай индексы только там, где они действительно улучшают производительность.