← Назад к вопросам
Как индексировать данные в столбце в БД по условию
2.2 Middle🔥 171 комментариев
#Базы данных и SQL
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Ответ
Индексирование по условию (Partial/Conditional Index) — это продвинутая техника оптимизации базы данных. Она позволяет создать индекс, включающий только строки, соответствующие определённому условию.
1. PostgreSQL — Filtered Index
-- Индекс только для активных пользователей
CREATE INDEX idx_active_users ON users(email)
WHERE status = "active";
-- Индекс для заказов с суммой > 1000
CREATE INDEX idx_high_orders ON orders(user_id)
WHERE total_amount > 1000;
-- Составной индекс с условием
CREATE INDEX idx_recent_deleted ON posts(author_id, created_at)
WHERE deleted_at IS NULL;
2. MySQL — Виртуальные столбцы
MySQL не имеет встроенной поддержки фильтрованных индексов:
-- Добавить столбец-флаг
ALTER TABLE users ADD COLUMN is_active_idx TINYINT
GENERATED ALWAYS AS (status = "active") STORED;
CREATE INDEX idx_active_users ON users(is_active_idx, email);
3. SQL Server — Filtered Index
CREATE NONCLUSTERED INDEX idx_active_products
ON Products(CategoryID, Price)
WHERE Status = "Active";
Миграция в Goose
-- Индекс для активных пользователей
CREATE INDEX idx_users_active_email
ON users(email)
WHERE deleted_at IS NULL
AND status = "active";
-- Индекс для недавних комментариев
CREATE INDEX idx_comments_recent
ON comments(post_id, created_at)
WHERE deleted_at IS NULL;
-- Индекс для незавершённых заказов
CREATE INDEX idx_orders_pending_user
ON orders(user_id, created_at)
WHERE status = "pending"
AND deleted_at IS NULL;
Java и JPA
@Entity
@Table(name = "tasks")
public class Task {
@Id
private Long id;
@Column(name = "user_id")
private Long userId;
@Column(name = "status")
private String status;
@Column(name = "priority")
private Integer priority;
@Column(name = "deleted_at")
private LocalDateTime deletedAt;
}
@Repository
public interface TaskRepository extends JpaRepository<Task, Long> {
@Query("SELECT t FROM Task t WHERE t.userId = :userId " +
"AND t.status IN ("open", "in_progress") " +
"AND t.deletedAt IS NULL " +
"ORDER BY t.priority DESC")
List<Task> findPendingTasks(@Param("userId") Long userId);
}
Анализ индекса
-- PostgreSQL: EXPLAIN
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM users
WHERE email = "test@example.com"
AND status = "active";
Случаи использования
- NULL значения: индексируйте только NOT NULL
CREATE INDEX idx_email_not_null ON users(email) WHERE email IS NOT NULL;
- Активные записи: индексируйте только активные
CREATE INDEX idx_active ON users(id) WHERE is_active = true;
- Недавние данные: индексируйте только свежие записи
CREATE INDEX idx_recent ON posts(author_id)
WHERE created_at > NOW() - INTERVAL "30 days";
- Мягкое удаление: индексируйте только неудалённые
CREATE INDEX idx_not_deleted ON orders(user_id) WHERE deleted_at IS NULL;
Преимущества
- Индекс меньше по размеру
- Быстрее обновляется
- Улучшает кэширование памяти
- Специфичен для частых запросов
- Экономит дисковое пространство
Недостатки
- Сложнее в обслуживании
- Не все базы данных поддерживают (MySQL)
- Требует планирования на основе паттернов запросов
Это мощный инструмент для оптимизации больших таблиц с миллионами записей.