Django objects.filter,这将是多么“昂贵”?

时间:2008-12-20 21:30:12

标签: python sql django search optimization

我正在尝试在Django中创建搜索视图。它是一个带有自由文本输入的搜索表单+一些可供选择的选项,因此您可以过滤年份等等。这是我到目前为止视图中的一些代码,它是进行过滤的部分。我想了解一下这对数据库服务器的成本有多大。

soknad_list = Soknad.objects.all()

if var1:
    soknad_list = soknad_list.filter(pub_date__year=var1)

if var2:
    soknad_list = soknad_list.filter(muncipality__name__exact=var2)

if var3:
    soknad_list = soknad_list.filter(genre__name__exact=var3)

# TEXT SEARCH
stop_word_list = re.compile(STOP_WORDS, re.IGNORECASE)
search_term = '%s' % request.GET['q']
cleaned_search_term = stop_word_list.sub('', search_term)
cleaned_search_term = cleaned_search_term.strip()
if len(cleaned_search_term) != 0:
    soknad_list = soknad_list.filter(Q(dream__icontains=cleaned_search_term) | Q(tags__icontains=cleaned_search_term) | Q(name__icontains=cleaned_search_term) | Q(school__name__icontains=cleaned_search_term))

if var1: soknad_list = soknad_list.filter(pub_date__year=var1) if var2: soknad_list = soknad_list.filter(muncipality__name__exact=var2) if var3: soknad_list = soknad_list.filter(genre__name__exact=var3) # TEXT SEARCH stop_word_list = re.compile(STOP_WORDS, re.IGNORECASE) search_term = '%s' % request.GET['q'] cleaned_search_term = stop_word_list.sub('', search_term) cleaned_search_term = cleaned_search_term.strip() if len(cleaned_search_term) != 0: soknad_list = soknad_list.filter(Q(dream__icontains=cleaned_search_term) | Q(tags__icontains=cleaned_search_term) | Q(name__icontains=cleaned_search_term) | Q(school__name__icontains=cleaned_search_term))

所以我要做的是,首先列出所有对象,然后检查哪些变量存在(我在前一点用GET获取这些变量)然后我过滤结果(如果它们存在)。但这似乎并不太优雅,它可能会有很多查询来实现结果,所以有更好的方法吗?

它完全符合我的要求,但我想有更好/更聪明的方法来做到这一点。有什么想法吗?

3 个答案:

答案 0 :(得分:4)

过滤器本身不执行查询,在您从查询中显式获取项目(例如get)之前不会执行任何查询,而list(query)也会执行它。

答案 1 :(得分:2)

您可以使用以下命令查看将生成的查询:

soknad_list.query.as_sql()[0]

然后,您可以将其放入数据库shell以查看查询所需的时间,或使用EXPLAIN(如果您的数据库后端支持它)来查看它的价格。

答案 2 :(得分:-1)

正如Aaron所提到的,你应该掌握将要对数据库运行的查询文本,并使用EXPLAIN(或其他某种方法)来查看查询执行计划。一旦掌握了查询的执行计划,就可以看到数据库本身发生了什么。有许多操作看起来非常昂贵,可以运行程序代码,这对于运行任何数据库都非常简单,特别是如果您提供数据库可以用来加速查询的索引。

如果我正确阅读了您的问题,您将检索Soknad表中所有行的结果集。获得这些结果后,您可以使用filter()方法来减少符合条件的结果。从查看Django文档看,它看起来像是在进行内存过滤而不是重新查询数据库(当然,这实际上取决于你使用的是哪个数据访问层而不是Django本身)。

最佳解决方案是使用全文搜索引擎(Lucene,ferret等)为您处理此问题。如果这不可用或不实用,那么下一个最佳选择是在向数据库发出查询并让数据库执行过滤之前构造查询谓词(WHERE子句)。

然而,与所有涉及数据库的事情一样,真正的答案是“它取决于”。最好的建议是使用接近生产的数据尝试几种不同的方法,并在确定问题的最终解决方案之前对其进行至少3次迭代的基准测试。在内存中过滤而不是在数据库中过滤可能同样快,甚至更快。