django:orm/sql在django过滤器中添加了额外的booleanfield或(sqltinyint)后,查询速度显著降低

rqenqsqc  于 2021-06-20  发布在  Mysql
关注(0)|答案(1)|浏览(347)

使用mysql最新版本django:
我有一个非常复杂的django查询,它运行得非常快——直到我添加了一个带有布尔字段的“and”——如下所示:

queriedForms = queryFormtype.form_set.filter(is_public=True) 
newQuery = queriedForms.filter(formrecordattributevalue__record_value__icontains=term['TVAL'], formrecordattributevalue__record_attribute_type__pk=rtypePK)
newQuery = newQuery.filter(flagged_for_deletion=False)
logger.info(newQuery.query)
term['count'] =  newQuery.count()

如果我去掉首字母“is\u public=true”或最后一个“flagged\u for\u deletion=false”,它的运行速度会非常快。如果将两者都用作过滤器,则count()函数的时间会增加大约2000%
不同的queryset.query输出如下:

SELECT `maqluengine_form`.`id`, `maqluengine_form`.`form_name`, `maqluengine_form`.`form_number`, `maqluengine_form`.`form_geojson_string`, `maqluengine_form`.`hierarchy_parent_id`, `maqluengine_form`.`is_public`, `maqluengine_form`.`project_id`, `maqluengine_form`.`date_created`, `maqluengine_form`.`created_by_id`, `maqluengine_form`.`date_last_modified`, `maqluengine_form`.`modified_by_id`, `maqluengine_form`.`sort_index`, `maqluengine_form`.`form_type_id`, `maqluengine_form`.`flagged_for_deletion` FROM `maqluengine_form` INNER JOIN `maqluengine_formrecordattributevalue` ON (`maqluengine_form`.`id` = `maqluengine_formrecordattributevalue`.`form_parent_id`) WHERE (`maqluengine_form`.`form_type_id` = 319 AND `maqluengine_form`.`is_public` = True AND `maqluengine_formrecordattributevalue`.`record_value` LIKE %seal% AND `maqluengine_formrecordattributevalue`.`record_attribute_type_id` = 18510 AND `maqluengine_form`.`flagged_for_deletion` = False)
SELECT `maqluengine_form`.`id`, `maqluengine_form`.`form_name`, `maqluengine_form`.`form_number`, `maqluengine_form`.`form_geojson_string`, `maqluengine_form`.`hierarchy_parent_id`, `maqluengine_form`.`is_public`, `maqluengine_form`.`project_id`, `maqluengine_form`.`date_created`, `maqluengine_form`.`created_by_id`, `maqluengine_form`.`date_last_modified`, `maqluengine_form`.`modified_by_id`, `maqluengine_form`.`sort_index`, `maqluengine_form`.`form_type_id`, `maqluengine_form`.`flagged_for_deletion` FROM `maqluengine_form` INNER JOIN `maqluengine_formrecordattributevalue` ON (`maqluengine_form`.`id` = `maqluengine_formrecordattributevalue`.`form_parent_id`) WHERE (`maqluengine_form`.`form_type_id` = 319 AND `maqluengine_form`.`is_public` = True AND `maqluengine_formrecordattributevalue`.`record_value` LIKE %seal% AND `maqluengine_formrecordattributevalue`.`record_attribute_type_id` = 18510)

第一种方法大约需要20/30秒来执行count(),而第二种方法只有两个booleanfield中的一个,执行count()所需的时间不到一秒
==========================================================编辑================================抱歉:既然问题不够明显--为什么添加一个额外的and和一个布尔字段会将查询时间增加+2000%?有没有人能帮忙找出原因。谢谢。

klr1opcd

klr1opcd1#

编辑=========================
还发现使用排除(is\u public=false)而不是筛选器(is\u public=true)与下面的解决方案具有相同的效果。有人知道为什么exclude()可以正常工作,而filter()不行吗?

我休息了一晚上后想出了解决办法:
--我保持查询的原样(我以后需要它,因为它会继续进行链式筛选)--我需要这个阶段的count()--这比使用额外的booleanfield花费的时间要长得多--我需要一个临时值列表来执行len():

queriedForms = queryFormtype.form_set.all()
newQuery = queriedForms.filter(formrecordattributevalue__record_value__icontains=term['TVAL'], formrecordattributevalue__record_attribute_type__pk=rtypePK)
newQuery = newQuery.filter(flagged_for_deletion=False)
tempQuery = newQuery.values_list('is_public',flat=True)
finalQuery = [entry for entry in tempQuery if entry != 'False'] #Remove any indices that contain "False"
term['count'] =  len(finalQuery)

在使用相同的技术之后,使用链式过滤器的计数要快得多,如果没有从过滤器中删除一个布尔值那么快的话。

相关问题