【发布时间】:2016-10-03 23:11:06
【问题描述】:
我的粗略模型:
class m_Interaction(models.Model):
fk_ip = models.ForeignKey('m_IP', on_delete=models.SET_NULL, null=True, related_name="interactions")
fk_query = models.ForeignKey('m_Query', on_delete=models.SET_NULL, null=True, related_name="interactions")
使用的数据库:SQLite
如果我执行这个查询集
m_Interaction.objects.filter(fk_query=None).filter(fk_ip__in=user.ips.all()).select_related('fk_query')
需要 5 秒。
如果我删除filter(fk_query=None) 语句,剩下的查询集
m_Interaction.objects.filter(fk_ip__in=user.ips.all()).select_related('fk_query')
只需 100 毫秒即可执行。
filter(fk_ip__in=user.ips.all()) 不应该贵很多吗?或者至少为什么filter(fk_query=None) 语句这么慢?它应该是一个简单的“与 Null 比较”的查找。
filter(fk_query=None) 的 SQL 查询:
SELECT "data_manager_m_interaction"."id",
"data_manager_m_interaction"."fk_ip_id",
"data_manager_m_interaction"."fk_query_id",
"data_manager_m_query"."id",
"data_manager_m_query"."fk_ip_id"
FROM "data_manager_m_interaction"
LEFT OUTER JOIN "data_manager_m_query"
ON ("data_manager_m_interaction"."fk_query_id" = "data_manager_m_query"."id")
WHERE ("data_manager_m_interaction"."fk_ip_id" IN (SELECT U0."id" FROM "data_manager_m_ip" U0 WHERE U0."fk_user_id" = 1339)
AND "data_manager_m_interaction"."fk_query_id" IS NULL)
ORDER BY "data_manager_m_interaction"."timestamp" ASC
LIMIT 1
没有filter(fk_query=None)的SQL查询:
SELECT "data_manager_m_interaction"."id",
"data_manager_m_interaction"."fk_ip_id",
"data_manager_m_interaction"."fk_query_id",
"data_manager_m_query"."id",
"data_manager_m_query"."fk_ip_id"
FROM "data_manager_m_interaction"
LEFT OUTER JOIN "data_manager_m_query"
ON ("data_manager_m_interaction"."fk_query_id" = "data_manager_m_query"."id")
WHERE "data_manager_m_interaction"."fk_ip_id" IN (SELECT U0."id" FROM "data_manager_m_ip" U0 WHERE U0."fk_user_id" = 1339)
ORDER BY "data_manager_m_interaction"."timestamp" ASC
LIMIT 1
解释查询计划(带过滤器):
[(0, 0, 0, 'SEARCH TABLE data_manager_m_interaction USING INDEX data_manager_m_interaction_c50f4040 (fk_query_id=?)'),
(0, 0, 0, 'EXECUTE LIST SUBQUERY 1'),
(1, 0, 0, 'SEARCH TABLE data_manager_m_ip AS U0 USING COVERING INDEX data_manager_m_ip_f569ccde (fk_user_id=?)'),
(0, 1, 1, 'SEARCH TABLE data_manager_m_query USING INTEGER PRIMARY KEY (rowid=?)'),
(0, 0, 0, 'USE TEMP B-TREE FOR ORDER BY')]
解释查询计划(不带过滤器)
[(0, 0, 0, 'SEARCH TABLE data_manager_m_interaction USING INDEX data_manager_m_interaction_c669518a (fk_ip_id=?)'),
(0, 0, 0, 'EXECUTE LIST SUBQUERY 1'),
(1, 0, 0, 'SEARCH TABLE data_manager_m_ip AS U0 USING COVERING INDEX data_manager_m_ip_f569ccde (fk_user_id=?)'),
(0, 1, 1, 'SEARCH TABLE data_manager_m_query USING INTEGER PRIMARY KEY (rowid=?)'),
(0, 0, 0, 'USE TEMP B-TREE FOR ORDER BY')]
【问题讨论】:
-
首先,您可以尝试
filter(fk_query__isnull=True)而不是fk_query=None看看是否有任何改进,但我会使用print your-query.query来查看原始sql 语句并查看差异。 -
我同意这似乎违反直觉。如果您更改过滤器的顺序或将它们组合成一个过滤器,会有什么不同吗?
filter(fk_query=None, fk_ip__in=user.ips.all()) -
你在用mysql吗?我怀疑你是。如果是这样,这个结果实际上并不令人惊讶。
-
感谢您的快速回复!我更新了我的问题。 @Shang Wang
filter(fk_query__isnull=True)没有区别。上面列出了原始查询。 @Håken Lid 顺序无关紧要 @e4c5 我正在使用 SQLite,甚至更糟:) 但在这种情况下这不应该是问题
标签: python django sqlite django-queryset django-filter