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

Какое условие не рекомендует использовать индексы?

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

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

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

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

Когда не рекомендуется использовать индексы

Индексы — мощный инструмент оптимизации запросов в базах данных, но они имеют свою цену. Существует ряд условий, когда создание индексов неэффективно или даже вредно.

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');

Практические рекомендации

Создавай индексы только если:

  1. Высокая селективность (>5% уникальных значений)
  2. Таблица достаточно большая (>100k строк) и часто используется в фильтрах
  3. Затраты на обновление индекса < выигрыш в SELECT запросах
  4. Столбец часто используется в WHERE, JOIN, ORDER BY запросах
  5. Память доступна для хранения индекса

Мониторинг неиспользуемых индексов

Проверь, какие индексы не приносят пользу:

-- 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;

Удали неиспользуемые индексы — они только замедляют обновления и занимают память.

Вывод

Индексы — это инструмент, требующий осознанного применения. Не добавляй индекс просто так. Профилируй запросы, анализируй план выполнения и создавай индексы только там, где они действительно улучшают производительность.

Какое условие не рекомендует использовать индексы? | PrepBro