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

Что такое индекс с условием в БД?

2.0 Middle🔥 61 комментариев
#Базы данных (SQL)

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

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

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

# Индекс с условием (Partial Index / Conditional Index)

Индекс с условием — это индекс БД, который индексирует только строки, удовлетворяющие определённому условию WHERE. Это мощная оптимизация для таблиц с большим количеством данных, где нужно часто искать по подмножеству.

Зачем это нужно

  1. Экономия места — индекс занимает меньше памяти, так как содержит только релевантные данные
  2. Быстрее обновления — когда мы добавляем/изменяем данные, индекс обновляется меньше
  3. Лучше производительность — для отфильтрованных запросов работает значительно быстрее
  4. Уменьшение fragmentation — индекс более компактный

SQL синтаксис (PostgreSQL)

-- Обычный индекс
CREATE INDEX idx_users_deleted ON users(id);

-- Индекс с условием — индексируем только активных пользователей
CREATE INDEX idx_users_active ON users(id) 
WHERE is_deleted = false;

-- Индекс для часто используемого фильтра
CREATE INDEX idx_orders_pending ON orders(created_at) 
WHERE status = 'pending';

-- Комплексное условие
CREATE INDEX idx_premium_users ON users(email)
WHERE subscription_plan = 'premium' 
  AND is_active = true
  AND created_at > NOW() - INTERVAL '1 year';

Практический пример

-- Таблица с 100 млн мягких удалений (soft deletes)
CREATE TABLE posts (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL,
    title VARCHAR(255),
    is_deleted BOOLEAN DEFAULT false,
    created_at TIMESTAMPTZ
);

-- БЕЗ частичного индекса
CREATE INDEX idx_posts_user ON posts(user_id);
-- Размер: ~5 GB (индексирует все 100 млн строк)

-- С частичным индексом
CREATE INDEX idx_posts_user_active ON posts(user_id) 
WHERE is_deleted = false;
-- Размер: ~1 GB (индексирует только активные посты, скажем 20%)

-- Запрос использует индекс
SELECT * FROM posts 
WHERE user_id = 42 AND is_deleted = false;
-- Query planner автоматически использует idx_posts_user_active

Django ORM синтаксис

from django.db import models
from django.db.models import Q, Index

class Post(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=255)
    is_deleted = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        indexes = [
            # Обычный индекс
            Index(fields=['user_id']),
            
            # Частичный индекс — только активные посты
            Index(
                fields=['user_id'],
                condition=Q(is_deleted=False),
                name='idx_posts_user_active'
            ),
            
            # Для часто используемых фильтров
            Index(
                fields=['user_id', 'created_at'],
                condition=Q(is_deleted=False),
                name='idx_posts_user_created'
            ),
        ]

SQLAlchemy синтаксис

from sqlalchemy import Column, Index, Boolean, String, ForeignKey
from sqlalchemy.orm import declarative_base

Base = declarative_base()

class Post(Base):
    __tablename__ = 'posts'
    
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('users.id'))
    title = Column(String(255))
    is_deleted = Column(Boolean, default=False)
    created_at = Column(DateTime(timezone=True))
    
    # Частичный индекс через DDL
    __table_args__ = (
        Index(
            'idx_posts_user_active',
            user_id,
            postgresql_where=is_deleted == False
        ),
    )

Когда использовать

Используй частичный индекс:

  • Soft delete паттерн (много деактивированных записей)
  • Фильтр по статусу (большая часть в одном статусе)
  • Временные данные (old data vs current)
  • Логические флаги (архивировано, одобрено и т.п.)

Не используй:

  • На маленьких таблицах (< 100k строк)
  • Если условие не стабильно (постоянно меняется)
  • Если много условий (раньше создай отдельный индекс)

Проверка использования индекса

-- PostgreSQL — посмотреть план запроса
EXPLAIN (ANALYZE, BUFFERS) 
SELECT * FROM posts 
WHERE user_id = 42 AND is_deleted = false;

-- Результат показывает, какой индекс использован
-- Index Scan using idx_posts_user_active on posts (cost=0.42..2.14)

Важные моменты

  • Условие в индексе предикат-зависимо — запрос должен точно совпадать с условием
  • Частичный индекс требует поддержки БД (PostgreSQL, SQLite поддерживают, MySQL ограниченно)
  • Не забывай об индексах при миграциях — update миграции с CREATE INDEX CONCURRENTLY на production

Это мощный инструмент для оптимизации БД, особенно при работе с soft deletes и логическими флагами.