Эффективность фильтра Django, который смешивает индексированные и неиндексированные поля?

#sql #django

#sql #django

Вопрос:

Предположим, у меня есть модель, подобная:

 class Widget(models.Model):
    a = models.CharField(db_index=True, unique=True)
    b = models.CharField()
  

и затем я выполняю фильтр, подобный:

 Widgets.objects.filter(a=a, b=b).get()
  

ожидаете ли вы, что производительность этого будет (1) такой же; или (2) хуже? — чем если бы вместо этого модель была определена как:

 class Widget(models.Model):
    a = models.CharField(db_index=True, unique=True)
    b = models.CharField(db_index=True)  # <--- now b is indexed
  

Я имею в виду, логически, поскольку a он индексируется и уникален, для некоторого значения a может быть найден не более одного результата, поэтому движок может просто выполнить поиск по a, а затем проверить, что поле результатов b является ожидаемым значением, без использования какого-либо индекса b .

Но на практике, будет ли сгенерированный SQL и базовый SQL-движок достаточно умны при планировании запросов, чтобы понять это? Является ли такое планирование запросов тривиальным?

Ответ №1:

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

ожидаете ли вы, что производительность этого будет (1) такой же; или (2) хуже?

Это будет примерно то же самое или немного хуже. В случае, если вы индексируете два поля. Обычно база данных будет искать индекс поля, который может ускорить работу больше всего. Возможно, b это лучше для этого, поэтому тогда он будет использовать индекс b и «сканировать» поле a .

Однако вы можете индексировать оба вместе. Вы делаете это с помощью indexes опции [Django-doc] параметров модели Meta [Django-doc]:

 class Widget(models.Model):
    a = models.CharField(db_index=True, unique=True)
    b = models.CharField(db_index=True)

    class Meta:
        indexes = [
            models.Index(fields=['a', 'b'])  # ← index together
        ]  

При этом, если a (или b ) уже может значительно сократить пространство поиска, ускорение будет не таким уж большим. Индекс используется для получения только тех частей диска, которые необходимы для базы данных. Однако, если второй индекс уменьшает количество элементов, но ему все равно нужны более или менее одинаковые сегменты, ускорение будет не таким большим, поскольку ввод-вывод (очень) часто является узким местом.