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

На какие типы полей не надо писать индекс?

1.0 Junior🔥 131 комментариев
#Другое

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

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

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

Типы полей, на которые не нужны индексы

Отличный вопрос о производительности БД. Есть поля, на которые индексы неэффективны или вредны:

1. Поля с низкой кардинальностью

Кардинальность — количество уникальных значений в поле. Если значений мало, индекс не поможет:

-- Плохо: только 2 уникальных значения (True/False)
CREATE INDEX idx_is_active ON users(is_active);

-- Лучше: без индекса, СУБД сама выберет оптимальную стратегию
SELECT * FROM users WHERE is_active = true;  -- Full table scan может быть быстрее

Примеры полей с низкой кардинальностью:

  • Булевы поля (true/false)
  • Поля со статусом ("draft", "published", "archived")
  • Пол ("M", "F")
  • Флаги и метки

2. Небольшие текстовые поля

На короткие VARCHAR индекс часто не дает выигрыша:

-- Сомнительно
CREATE INDEX idx_gender ON users(gender);  -- Поле с 2-3 значениями

-- Тем более на очень коротких полях
CREATE INDEX idx_country_code ON users(country_code);  -- 2-3 символа

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

3. Большие текстовые поля без специальных индексов

Обычные B-tree индексы неэффективны для больших текстов:

-- Плохо: обычный индекс не поможет
CREATE INDEX idx_description ON products(description);  -- TEXT или LONGTEXT

-- Хорошо: используем FULLTEXT индекс
CREATE FULLTEXT INDEX idx_description_ft ON products(description);
SELECT * FROM products WHERE MATCH(description) AGAINST('keyword');

4. Поля, которые редко используются в WHERE

Если поле почти никогда не используется в условиях поиска:

# Модель
class Article:
    id = Column(Integer, primary_key=True)
    title = Column(String, index=True)  # Часто ищут по заголовку
    content = Column(Text)  # Редко ищут по содержимому
    views_count = Column(Integer)  # Просто число для отображения
    created_at = Column(DateTime, index=True)  # Часто фильтруют по дате

5. Поля с частыми INSERT/UPDATE

Индексы нужно обновлять при каждой вставке. Если вставок больше чем чтений:

-- Может быть неэффективно, если очень много вставок
CREATE INDEX idx_temp_flag ON logs(is_temp);

-- Логи с множеством вставок, минимум чтений
INSERT INTO logs (message, is_temp) VALUES ('...', true);  -- Частая операция
INSERT INTO logs (message, is_temp) VALUES ('...', true);
INSERT INTO logs (message, is_temp) VALUES ('...', true);

6. BLOB и бинарные данные

Лучше не индексировать бинарные и очень большие данные:

-- Не нужен индекс
CREATE TABLE files (
    id INT PRIMARY KEY,
    name VARCHAR(255) INDEX,  -- По имени — окей
    content LONGBLOB  -- Индекс тут бесполезен
);

7. JSON поля (осторожно)

Обычный индекс на JSON малоэффективен:

-- Неправильно
CREATE INDEX idx_metadata ON users(metadata);  -- JSON

-- Правильно (если нужно)
CREATE INDEX idx_metadata_type 
    ON users((JSON_EXTRACT(metadata, '$.type')));

8. Вычисляемые поля (которые редко фильтруют)

-- Не нужен индекс
CREATE TABLE orders (
    id INT PRIMARY KEY,
    price DECIMAL,
    quantity INT,
    total DECIMAL GENERATED ALWAYS AS (price * quantity)  -- Без индекса
);

Практический пример для Python проекта

from sqlalchemy import Column, Integer, String, DateTime, Boolean, Index
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    
    id = Column(Integer, primary_key=True)
    
    # Индексируем: часто ищут пользователей по email
    email = Column(String(255), unique=True, index=True)
    
    # Индексируем: часто сортируют по дате создания
    created_at = Column(DateTime, index=True)
    
    # Индексируем: фильтруют по организации
    organization_id = Column(Integer, index=True)
    
    # НЕ индексируем: низкая кардинальность (true/false)
    is_active = Column(Boolean)  # Нет индекса
    
    # НЕ индексируем: редко используется в WHERE
    phone = Column(String(20))  # Нет индекса
    
    # НЕ индексируем: большой текст
    bio = Column(String(1000))  # Нет индекса

Правило: когда писать индекс

Пиши индекс если:

  • Поле часто используется в WHERE, JOIN, ORDER BY
  • Высокая кардинальность (много уникальных значений)
  • Больше SELECTов чем INSERTs/UPDATEs

Не пиши индекс если:

  • Низкая кардинальность (< 10 уникальных значений)
  • Поле редко в условиях
  • Огромный текст (нужен FULLTEXT)
  • Много вставок, мало чтений

Проверка эффективности индекса

-- PostgreSQL: посмотреть использованные индексы
EXPLAIN ANALYZE SELECT * FROM users WHERE is_active = true;

-- Если видишь "Seq Scan" вместо "Index Scan", индекс не помог

Вывод

Не пиши индексы на:

  1. Низкокардинальные поля
  2. Редко используемые в WHERE
  3. Большие текстовые поля
  4. Часто обновляемые поля с редкими чтениями
  5. Булевы и флаги

Лучше начать без индексов, потом добавлять по результатам профилирования.

На какие типы полей не надо писать индекс? | PrepBro