首页 > 解决方案 > 上索引似乎不适用于 iexact Django 字段查找

问题描述

我有一些引用(字符串),我想用它们来过滤不区分大小写的完全匹配的查询。为此,我使用了iexactDjango 字段查找。

Model.objects.filter(column1__iexact=reference)

由于该表上有大量行,因此我想创建一个索引来加快查询速度。Django 使用 UPPER 函数来执行iexact查找。所以我创建了以下迁移(数据库是 Postgresql):

class Migration(migrations.Migration):

    dependencies = [
        ('app', 'previous_migr'),
    ]

    operations = [
        migrations.RunSQL(
            sql=r'CREATE INDEX "index_name_idx" ON "table" (UPPER("column1") );',
            reverse_sql=r'DROP INDEX "index_name_idx";'
        ),
    ]

不幸的是,查询时似乎没有使用此索引。

为什么我会这样想?以下是请求时间:

这是生成的(截断的)SQL 查询:

SELECT "table"."id" FROM "table" 

WHERE (
    "table"."is_removed" = false 
    AND (UPPER("table"."column1"::text) = UPPER('blablabla') 
    OR UPPER("ordering_order"."column2"::text) = UPPER('blablabla'))) 
ORDER BY "table"."id" ASC
) 

我的迁移有问题吗?还有其他选择可以以良好的性能执行此查询吗?

标签: djangodatabasepostgresqlindexing

解决方案


Upper您可以使用查询中的表达式进行过滤,因此:

from django.db.models import Upper

Model.objects.annotate(
    column1_upper=Upper('column1')
).filter(column1_upper=reference.upper())

或者在中,我们可以使用 a.alias(…)来稍微提高性能:

Model.objects.alias(
    column1_upper=Upper('column1')
).filter(column1_upper=reference.upper())

然而,以上不是不区分大小写的搜索。当您将两个项目都转换为小写/大写时,假设两个项目是等价的,这是一个常见的错误。例如,在德语中,eszett ß为大写字母'SS',其他字符没有小写/大写变体。为了匹配大小写不变,您需要看一下 casefolding。


推荐阅读