Django-提高“ startswith”性能

Max*_*ysh 3 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')
Run Code Online (Sandbox Code Playgroud)

我已经在模型中添加了索引,但是...根本不使用它。但是,在没有以下情况的情况下进行普通过滤时,索引确实起作用startswith

# This line is fast:
Worker.objects.filter(name='John')
Run Code Online (Sandbox Code Playgroud)

为什么不使用索引startswith

Max*_*ysh 6

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

解决方案:添加带有特殊运算符类的附加索引:

CREATE INDEX "appname_model_field_like_idx" 
ON "appname_model" ("fieldname" varchar_pattern_ops);
Run Code Online (Sandbox Code Playgroud)

一步步:

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

    python3 manage.py makemigrations appName --empty
    
    Run Code Online (Sandbox Code Playgroud)
  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";'
            ),
        ]
    
    Run Code Online (Sandbox Code Playgroud)