在QuerySet中按索引获取元素的最快方法

时间:2018-02-12 18:11:12

标签: django django-queryset

考虑到大约有500万个对象,我试图在Django中为我的系统创建节省时间的搜索功能。

这是我设置查询的方式:

objects_found = (Model.objects.extra(where=["CHAR_LENGTH(attribute) > 300"])).filter(attribute__trigram_similar=query)

我知道这个QuerySet尚未完全评估,而且这正是我不想要的。

例如,要完成评估设置QuerySet,请执行以下操作:

list(objects_found)

大约需要60秒。

如果我想以经典方式获取设置QuerySet的第一项,它仍然需要约60秒,因为查询是针对所有对象启动的:

objects_found[0]

但如果我使用像first()这样的方法:

objects_found.first()

大约需要9秒,这意味着不会评估完整的QuerySet。

让我们考虑objects_found有500个对象。如果我需要做这样的事情怎么办?

objects_found[40]

或者这个:

objects_found[:15]

以时间有效的方式?

p.s slicing确实在db级别创建了offset选项,但由于某种原因没有时间差异。

因此,代码不会搜索所有500个对象,而只会搜索4015个对象。

Django QuerySet中是否有任何实现可以完成此操作?

1 个答案:

答案 0 :(得分:1)

您可以按照limiting querysets文档

中的说明对其进行切片来限制查询
objects_found = (Model.objects.extra(where=["CHAR_LENGTH(attribute) > 300"])).filter(attribute__trigram_similar=query)[:15]

您的查询在数据库上非常困难,像CHAR_LENGTH这样的函数不是运行每个查询运行时的最佳选择,因此您可能可以将长度提取到整数行而不是执行CHAR_LENGTH。

关于trigram你可以创建索引 https://www.postgresql.org/docs/9.1/static/pgtrgm.html#AEN143603

此外,如果您更喜欢通过Django创建索引,那么以下资源可能很有用 https://vxlabs.com/2018/01/31/creating-a-django-migration-for-a-gist-gin-index-with-a-special-index-operator/