Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Ответ
Индексирование — критический фактор производительности БД. Выбор полей для индексирования требует анализа паттернов запросов и баланса между скоростью чтения и затратами на запись.
Приоритет индексирования
1. Обязательно индексировать
Primary Key (PK)
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id; // Индекс автоматически
}
Всегда индексируется по умолчанию.
Foreign Keys (FK)
@Entity
public class Order {
@ManyToOne
@JoinColumn(name = "user_id")
private User user; // Нужен индекс для JOINов
}
Поля в WHERE условиях
-- Частый запрос:
SELECT * FROM users WHERE email = ?;
SELECT * FROM orders WHERE status = ?;
SELECT * FROM posts WHERE created_at > ?;
Индексируйте эти поля:
@Entity
public class User {
@Column(unique = true)
@Index(name = "idx_email")
private String email;
}
@Entity
public class Order {
@Column
@Index(name = "idx_status")
private OrderStatus status;
}
@Entity
public class Post {
@Column
@Index(name = "idx_created_at")
private LocalDateTime createdAt;
}
2. Высокий приоритет
Поля в ORDER BY
SELECT * FROM posts ORDER BY created_at DESC LIMIT 10;
Поля в GROUP BY
SELECT category, COUNT(*) FROM products GROUP BY category;
Поля в JOIN условиях
SELECT * FROM orders o
JOIN payments p ON o.id = p.order_id
WHERE o.user_id = ?;
Пример индекса:
@Entity
@Table(indexes = {
@Index(name = "idx_category", columnList = "category"),
@Index(name = "idx_created_at", columnList = "created_at DESC")
})
public class Product {
private String category;
private LocalDateTime createdAt;
}
3. Составные индексы (Composite Indexes)
Для часто используемых комбинаций:
@Entity
@Table(indexes = {
@Index(
name = "idx_user_status_date",
columnList = "user_id, status, created_at DESC"
)
})
public class Transaction {
private UUID userId;
private TransactionStatus status;
private LocalDateTime createdAt;
}
Практический пример:
// Запрос использует индекс полностью
List<Transaction> txns = repository.findByUserIdAndStatusOrderByCreatedAtDesc(
userId,
TransactionStatus.COMPLETED
);
// SQL: WHERE user_id = ? AND status = ? ORDER BY created_at DESC
// Индекс (user_id, status, created_at DESC) отлично подходит
4. Низкий приоритет (редко индексировать)
Поля с низкой селективностью
@Entity
public class User {
@Column
// Индекс на is_active НЕ НУЖЕН — только 2 значения
private boolean isActive;
@Column
// Индекс на gender может быть бесполезен — только 3 значения
private String gender;
}
BLOB/TEXT поля
@Entity
public class Article {
@Lob
private String content; // Не индексируйте, слишком много данных
@Index(name = "idx_title") // Заголовок — ОК
private String title;
}
Пример правильной схемы
@Entity
@Table(
name = "users",
indexes = {
@Index(name = "idx_email", columnList = "email", unique = true),
@Index(name = "idx_username", columnList = "username", unique = true),
@Index(name = "idx_created_at", columnList = "created_at DESC"),
@Index(name = "idx_status_created", columnList = "status, created_at DESC")
}
)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;
@Column(unique = true)
private String email;
@Column(unique = true)
private String username;
@Column
private UserStatus status;
@Column
private LocalDateTime createdAt;
@Lob
private String bio; // Без индекса
}
Проверка использования индексов
// PostgreSQL
EXPLAIN ANALYZE
SELECT * FROM users WHERE email = test@example.com;
// MySQL
EXPLAIN
SELECT * FROM users WHERE email = test@example.com;
Антипаттерны
❌ Индексирование всех полей — увеличивает размер БД ❌ Полнотекстовый поиск в обычном индексе ❌ Индексы на вычисляемых столбцах без генерируемых индексов
Правило 80/20
Обычно 20% индексов решают 80% проблем производительности. Сначала индексируйте:
- PRIMARY KEY и FOREIGN KEYS
- Поля в WHERE условиях
- Поля в JOIN условиях
- Составные индексы для частых комбинаций
Затем профилируйте и добавляйте дополнительные индексы по необходимости.