我必须筛选一个大约 2400 万的模型。实例(记录)。 我需要根据从 url kwarg 获得的一些名称来过滤它们,我有这样的东西:
Model.objects.filter(field__icontains=self.kwargs['kwarg']).values()
在视图上。
这绝对没有效率,因为页面速度非常慢并且需要 CPU 进行大量处理。我该如何解决这个问题?
提前感谢您的回答!
您必须在该字段上创建索引。但它必须是一个特定的索引才能与
__icontains
过滤器相关。
模型定义中的
db_index=True
创建了一个B树索引,可以处理相等和范围查询。这仅对 django 中的 __exact
文件管理器(SQL 中的 = 运算符)有用。即使与 __iexact
过滤器一起使用也不会使用它,因为该过滤器在 SQL 中 = 运算符之前对数据使用 SQL 操作 UPPER。这需要自定义索引或使用 Django 3.2+ OpClass 表达式。
对于
__contains
过滤器,LIKE 运算符在 SQL 中使用,并且需要 Postgres Trigram 扩展来进行全文搜索。特别是杜松子酒指数似乎效果最好。
__icontains
过滤器可以使用Gin索引,但与__iexact
过滤器一样,它还在LIKE运算符之前对数据使用UPPER SQL操作。所以它需要一个自定义的 Gin 索引或使用 Django 3.2+ 的 OpClass
表达式。
所以对于后者,我必须在模型中使用它:
from django.contrib.postgres.indexes import GinIndex, OpClass
class Meta:
indexes = [
GinIndex(fields=['name'], name='name_gin_index',
opclasses=['gin_trgm_ops'])
]
您还需要在创建索引之前将
TrigramExtension()
(from django.contrib.postgres.operations import TrigramExtension
) 添加到迁移操作列表中来激活迁移中的 Trigram 扩展