Продвинутый Django 5 для продолжающих

Прогресс по курсу:  0/193

3.3 Индексы PostgreSQL
3 из 3 шагов пройдено

Индекс диапазона блоков (BRIN)

Наш последний пример - найти сотрудников, которые имеют дату создания равное определенному значению. В нашем случае мы попробуем найти сотрудников, которые были созданы ранее 2023 года. Для этого изменим наши представления:

def homePageView(request):
    employees = Employee.objects.filter(created__year__lte=2022)
    return render(request, 'list.html', {'employees': employees})

Запустим сервер и проверим:

Теперь давайте применим индекс B-Tree в поле created, чтобы повысить скорость запроса.

Применение индекса снова сработало с точки зрения оптимизации времени выполнения. К сожалению, мы сталкиваемся с той же проблемой, что и раньше, при проверке размера индекса, который достигает около 10% общего размера таблицы.

Вывод прост - размер индекса довольно велик или, по крайней мере, может быть меньше. К счастью, есть один индекс, который идеально соответствует нашей текущей ситуации.

Индекс BRIN расшифровывается как "Block Range Index" (Индекс диапазона блокировки) и группирует значения в столбце в диапазоны страниц JSON. Эта функция PostgreSQL лучше всего работает, когда данные естественным образом сортируются на диске, что не совсем соответствует нашему примеру, у нас дата создания у всех почти одинаковая. Но главное преимущество этой ситуации заключается в том, что они отсортированы в нашей таблице по возрастанию.

Использование индекса BRIN требует импорта того же пакета, что и Hash Index:

from django.contrib.postgres.indexes import BrinIndex

class Employee(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    about = models.CharField(max_length=10000)
    age = models.SmallIntegerField(null=True)
    created = models.DateTimeField(default=timezone.now)
    work_experience = models.SmallIntegerField(default=0, null=True)
    contact = models.OneToOneField(Contact, on_delete=models.CASCADE, null=True)
    department = models.ForeignKey(Department, on_delete=models.CASCADE, default=None, null=True)

    class Meta:
        indexes = (
            BrinIndex(fields=('created',), name="hr_employee_created_ix",
                      pages_per_range=2
                      ),
        )

    def __str__(self):
        return f'{self.first_name} {self.last_name}'

Выполним миграции и запустим сервер еще раз:

Когда мы проверяем запрос, мы видим, что индекс правильно использовался ядром базы данных. Обычно, время выполнения немного больше, чем при использовании индекса B-Tree. Это связано с тем, что индексы BRIN требуют больше времени, так как они проверяют все значения в контейнерах. В нашем случае время уменьшилось, так как у нас все даты создания работников одинаковые.

Плюс заключается в том, что он оптимизирует дисковое пространство, в нашем случае мы смогли использовать примерно в 5 раз меньше места.

Существует способ обеспечить лучшую оптимизацию времени выполнения индекса BRIN. Решение состоит в том, чтобы поэкспериментировать со значением pages_per_row в самом индексе. Это может немного увеличить размер индекса, поэтому здесь нужно найти баланс.

Резюме:

  • Значительно уменьшает размер индекса.
  • Отлично подходит для любых дат или естественно растущих значений в столбце.
  • Может быть бесполезно, когда данные естественным образом не сортируются на диске.
  • Не оптимизирует скорость.

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