Django — 提高 `startswith` 的性能
Posted
技术标签:
【中文标题】Django — 提高 `startswith` 的性能【英文标题】:Django — improve `startswith` performance 【发布时间】:2018-09-15 21:22:30 【问题描述】:如何提高以下查询的性能?
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
不使用索引?
【问题讨论】:
【参考方案1】:问题在于startswith
表达式转换为包含LIKE
运算符的SQL 查询,它没有利用默认索引。
解决方案:添加一个带有特殊operator class的附加索引:
CREATE INDEX "appname_model_field_like_idx"
ON "appname_model" ("fieldname" varchar_pattern_ops);
一步一步:
首先,创建一个空迁移:
python3 manage.py makemigrations appName --empty
添加自定义 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";'
),
]
【讨论】:
reverse_sql
的附加样式点。丢失时总是令人沮丧。
似乎 Django 已经自动添加了这个索引(可能只有当引用字段上已经有索引时 - 我不确定)。【参考方案2】:
如果您的后端是 mysql,请尝试使用不区分大小写的 istartswith
来使用索引:
Worker.objects.filter(name__istartswith='John')
【讨论】:
以上是关于Django — 提高 `startswith` 的性能的主要内容,如果未能解决你的问题,请参考以下文章
AttributeError:“元组”对象没有属性“startswith”
在服务器上运行 collectstatic:AttributeError:“PosixPath”对象没有属性“startswith”