Django - 提高`startswith`性能

时间:2018-04-05 22:59:10

标签: python sql django postgresql django-orm

如何提高以下查询的效果?

class Worker(models.Model):
    name = models.CharField(max_length=32, db_index=True)

# This line is slow:
Worker.objects.filter(name__startswith='John')

我已经为模型添加了索引,但是......它根本就没用过。 然而,当我在没有startswith的情况下进行普通过滤时,索引会启动:

# This line is fast:
Worker.objects.filter(name='John')

为什么索引不与startswith一起使用?

2 个答案:

答案 0 :(得分:4)

问题是startswith表达式转换为包含LIKE运算符的SQL查询,该运算符不利用默认索引。

解决方案:使用特殊operator class添加其他索引:

CREATE INDEX "appname_model_field_like_idx" 
ON "appname_model" ("fieldname" varchar_pattern_ops);

一步一步:

  1. 首先,创建一个空迁移:

    python3 manage.py makemigrations appName --empty
    
  2. 添加自定义RunSQL命令:

    class Migration(migrations.Migration):
    
        dependencies = [
            ('stats', '0002_auto_2010213_0159.py'),
        ]
    
        operations = [
            migrations.RunSQL(
                sql=r'''CREATE INDEX "appname_model_field_like_idx" 
                        ON "appname_model" ("fieldname" varchar_pattern_ops);''',
                reverse_sql=r'DROP INDEX "appname_model_field_like_idx";'
            ),
        ]
    

答案 1 :(得分:0)

如果您的后端是MySQL,请尝试使用不区分大小写的istartswith来使用索引:

Worker.objects.filter(name__istartswith='John')