Какие способы создания индексов базы данных существуют в Django ORM?

Ответ

В Django ORM есть несколько способов определить индексы для полей модели, что критически важно для ускорения операций поиска (SELECT) по этим полям.

1. Простой индекс на одно поле (db_index=True)

Это самый простой способ добавить индекс для одного столбца. Используется как опция поля модели.

from django.db import models

class User(models.Model):
    # Создаст индекс для поля username
    username = models.CharField(max_length=100, db_index=True, unique=True)

2. Составные и именованные индексы (Meta.indexes)

Для более сложных случаев, таких как индексы по нескольким полям или для задания уникальных имен, используется класс Meta внутри модели. Этот подход более гибкий и является рекомендуемым.

from django.db import models

class User(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

    class Meta:
        indexes = [
            # Индекс по одному полю (аналог db_index=True)
            models.Index(fields=['first_name']),
            # Составной индекс по двум полям с кастомным именем
            models.Index(fields=['last_name', 'first_name'], name='full_name_idx'),
        ]

3. Функциональные индексы (Django 3.2+)

Позволяют создавать индексы на основе выражений или функций базы данных. Очень полезно для регистронезависимого поиска.

from django.db import models
from django.db.models.functions import Lower

class User(models.Model):
    username = models.CharField(max_length=100)

    class Meta:
        indexes = [
            # Индекс по значению поля в нижнем регистре
            models.Index(Lower('username'), name='username_lower_idx'),
        ]

Что нужно помнить:

  • Производительность: Индексы значительно ускоряют чтение (поиск, фильтрацию), но немного замедляют операции записи (INSERT, UPDATE), так как индекс тоже нужно обновлять.
  • Миграции: После добавления или изменения индексов в модели необходимо создать и применить миграции:
    python manage.py makemigrations
    python manage.py migrate

Ответ 18+ 🔞

А, ну ты глянь, какой вопрос подкинули! Про индексы в Django, да? О, это, блядь, святое! Без них твоя база данных будет ползать, как черепаха в сиропе, а ты будешь ждать запросы до второго пришествия. Так что слушай сюда, разжуём по косточкам.

1. Простейший индекс, чтоб его, на одно поле (db_index=True)

Это как взять и приклеить стикер "Быстрый доступ" на одну коробку в подвале. Делается прямо в описании поля, проще некуда.

from django.db import models

class User(models.Model):
    # Вот тут, смотри, создаст индекс для username. И unique ещё, чтоб дважды не сували.
    username = models.CharField(max_length=100, db_index=True, unique=True)

Вот и всё, ебушки-воробушки. Django сам всё приберёт за тобой.

2. Составные и именованные индексы, чтоб их (Meta.indexes)

А вот это уже для продвинутых распиздяев, которые хотят контролировать процесс. Хочешь индекс по двум полям сразу? Или имя ему своё, красивое, дать? Пожалуйста! Всё через класс Meta внутри модели.

from django.db import models

class User(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

    class Meta:
        indexes = [
            # Просто индекс по имени, как db_index=True, но тут.
            models.Index(fields=['first_name']),
            # А вот это, сука, составной! По фамилии и имени. И имя ему 'full_name_idx', чтоб не абы как.
            models.Index(fields=['last_name', 'first_name'], name='full_name_idx'),
        ]

Теперь поиск и по фамилии, и по связке "фамилия-имя" будет летать. Удивление пиздец, как быстро!

3. Функциональные индексы (для тех, кто на Django 3.2 и выше)

Это вообще магия, блядь. Индекс не просто по полю, а по результату какой-то функции от этого поля! Чаще всего нужно для того, чтобы искать без учёта регистра и не охуевать от скорости.

from django.db import models
from django.db.models.functions import Lower

class User(models.Model):
    username = models.CharField(max_length=100)

    class Meta:
        indexes = [
            # Индекс не по 'username', а по 'LOWER(username)'! Гениально и просто.
            models.Index(Lower('username'), name='username_lower_idx'),
        ]

Теперь filter(username__iexact='vasya') будет работать в разы шустрее. Чих-пых тебя в сраку, какая красота!

А теперь, сука, главное, что нужно помнить:

  • Скорость: Индексы — это как турбонаддув для SELECT запросов. Но! Каждый раз, когда ты что-то пишешь в базу (INSERT, UPDATE), этому турбонаддуву тоже приходится шевелиться и обновляться. Так что добавляй с умом, а не на каждое поле.
  • Миграции: Ты же не думал, что просто код написал и всё? Нет, блядь! Надо сказать Django: "Эй, чувак, я тут индекс добавил, подвинься". Делается это так:
    python manage.py makemigrations
    python manage.py migrate

    Не забудь, а то будешь потом думать, почему ничего не работает, а оно, блядь, миграцию не накатило.

Вот так вот, коротко и без воды. Индексы — твои лучшие друзья в борьбе с медленными запросами. Используй с умом, и будет тебе счастье.