← Назад к вопросам
Как создаются индексы в Django ORM?
2.0 Middle🔥 181 комментариев
#Django#Базы данных (SQL)
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как создаются индексы в Django ORM
Индекс в БД ускоряет поиск данных, создавая отсортированную структуру. Django ORM предоставляет несколько способов создать индексы как в модели, так и через миграции.
1. Индекс на одно поле
from django.db import models
class User(models.Model):
# Параметр db_index=True создаёт индекс
email = models.EmailField(unique=True) # unique автоматически создаёт индекс
username = models.CharField(max_length=100, db_index=True)
class Meta:
# Или в Meta если нужен индекс на существующее поле
indexes = [
models.Index(fields=['username']),
]
2. Составной индекс (на несколько полей)
class Article(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
published_date = models.DateField()
status = models.CharField(max_length=10)
class Meta:
indexes = [
# Индекс на несколько полей
models.Index(fields=['author', 'published_date']),
# Со специальным именем
models.Index(
fields=['author', 'status'],
name='author_status_idx'
),
]
3. Индекс с условием (partial index)
from django.db.models import Q, Index
class Product(models.Model):
name = models.CharField(max_length=200)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
indexes = [
# Индекс только для активных товаров
Index(
fields=['name'],
name='active_products_idx',
condition=Q(is_active=True) # Только active
),
# Более сложное условие
Index(
fields=['created_at'],
condition=Q(is_active=True) & Q(created_at__gte='2024-01-01')
),
]
4. Уникальный индекс
class Email(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
email = models.EmailField()
class Meta:
constraints = [
# Уникальность на два поля вместе
models.UniqueConstraint(
fields=['user', 'email'],
name='unique_user_email'
),
]
5. Индекс на выражение
from django.db.models import F, Index
from django.db.models.functions import Lower
class Category(models.Model):
name = models.CharField(max_length=100)
class Meta:
indexes = [
# Индекс на lowercase значения
Index(
models.F('name').asc(nulls_last=True),
name='name_lower_idx'
),
# Или с функцией
Index(
fields=['name'],
name='name_idx'
),
]
6. Порядок сортировки в индексе
class Order(models.Model):
customer = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
total = models.DecimalField(max_digits=10, decimal_places=2)
class Meta:
indexes = [
# DESC для created_at, ASC для total
models.Index(
fields=['-created_at', 'total'],
name='recent_orders_idx'
),
]
7. Хеш-индекс
class Document(models.Model):
content = models.TextField()
class Meta:
indexes = [
# HASH индекс для длинных строк (если БД поддерживает)
models.Index(
fields=['content'],
name='content_hash_idx',
opclasses=['hash'] # PostgreSQL feature
),
]
8. Проверка индексов в БД
# management command для просмотра индексов
# python manage.py sqlsequencereset app
# Или явно
from django.core.management import call_command
import io
import sys
out = io.StringIO()
call_command('sqlmigrate', 'app', '0001', stdout=out)
print(out.getvalue()) # Покажет CREATE INDEX запросы
9. Миграция: добавление индекса
# После изменения модели
# python manage.py makemigrations
# python manage.py migrate
# Сгенерированная миграция будет что-то вроде:
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('myapp', '0001_initial'),
]
operations = [
migrations.AddIndex(
model_name='article',
index=models.Index(
fields=['author', 'published_date'],
name='author_pub_idx'
),
),
]
10. Ручное создание индекса через миграцию
from django.db import migrations
from django.db.models import Index, Q
class Migration(migrations.Migration):
dependencies = []
operations = [
migrations.AddIndex(
model_name='product',
index=Index(
fields=['name', '-created_at'],
name='product_search_idx',
condition=Q(is_active=True)
),
),
]
11. Удаление индекса
from django.db import migrations
class Migration(migrations.Migration):
dependencies = []
operations = [
migrations.RemoveIndex(
model_name='article',
name='author_status_idx',
),
]
12. БД-специфичные индексы (PostgreSQL)
from django.contrib.postgres.indexes import BTreeIndex, BrinIndex
class BigTable(models.Model):
data = models.DateTimeField()
value = models.IntegerField()
class Meta:
indexes = [
# BRIN индекс для больших таблиц
BrinIndex(
fields=['data'],
name='data_brin_idx'
),
# Обычный BTree
BTreeIndex(
fields=['value'],
name='value_btree_idx'
),
]
13. Анализ плана запроса
from django.db import connections
# Посмотреть план выполнения запроса
cursor = connections['default'].cursor()
cursor.execute("""
EXPLAIN ANALYZE
SELECT * FROM myapp_article
WHERE author_id = 1 AND published_date > '2024-01-01'
""")
print(cursor.fetchall())
# Выведет информацию об использовании индекса
14. Best practices
# ✓ Хорошо: Индекс на поле для фильтрации
class Post(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, db_index=True)
status = models.CharField(max_length=10, db_index=True)
created_at = models.DateTimeField(auto_now_add=True, db_index=True)
# ✓ Хорошо: Составной индекс для JOIN
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE)
author = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
indexes = [
models.Index(fields=['post', 'author']),
]
# ✗ Плохо: Слишком много индексов
class BadModel(models.Model):
field1 = models.CharField(db_index=True)
field2 = models.CharField(db_index=True)
field3 = models.CharField(db_index=True)
# Индекс на каждое поле замедляет write операции!
# ✓ Хорошо: Индекс с условием для экономии
class Document(models.Model):
status = models.CharField(max_length=10)
content = models.TextField()
class Meta:
indexes = [
# Индекс только на active документы
models.Index(
fields=['status'],
condition=models.Q(status='published')
),
]
15. Инструменты для анализа
# Посмотреть все миграции
python manage.py showmigrations
# SQL для миграции
python manage.py sqlmigrate app 0002
# Чтобы увидеть индексы в БД (PostgreSQL)
psql -c "\di" database_name
# MySQL
SHOW INDEXES FROM table_name;
Заключение
Индексы в Django создаются через:
db_index=Trueна полях (простой способ)Meta.indexesсо спискомmodels.Index(для составных и сложных)Meta.constraintsдля уникальных индексов- Миграции для добавления/удаления
Главное правило: создавай индексы на полях, по которым часто фильтруешь, но помни что каждый индекс замедляет write операции. Баланс — ключ к производительности.