【发布时间】:2018-04-22 16:00:00
【问题描述】:
我正在编写的应用程序中有一个.exists() 查询。我要优化它。
当前的 ORM 表达式生成如下所示的 SQL:
SELECT DISTINCT
(1) AS "a",
"the_model"."id",
... snip every single column on the_model
FROM "the_model"
WHERE (
...snip criteria...
LIMIT 1
解释计划如下所示:
Limit (cost=176.60..176.63 rows=1 width=223)
-> Unique (cost=176.60..177.40 rows=29 width=223)
-> Sort (cost=176.60..176.67 rows=29 width=223)
Sort Key: id, ...SNIP...
-> Index Scan using ...SNIP... on ...SNIP... (cost=0.43..175.89 rows=29 width=223)
Index Cond: (user_id = 6)
Filter: ...SNIP...
如果我手动修改上面的 SQL 并删除单个表列,它看起来像这样:
SELECT DISTINCT
(1) AS "a",
FROM "the_model"
WHERE (
...snip criteria...
LIMIT 1
解释计划显示的步骤更少,这很棒。
Limit (cost=0.43..175.89 rows=1 width=4)
-> Unique (cost=0.43..175.89 rows=1 width=4)
-> Index Scan using ...SNIP... on ...SNIP... (cost=0.43..175.89 rows=29 width=4)
Index Cond: (user_id = 6)
Filter: ...SNIP...
我可以通过从查询中删除 DISTINCT 关键字来更进一步,从而产生更浅的执行计划,尽管这里节省的成本很小:
Limit (cost=0.43..6.48 rows=1 width=4)
-> Index Scan using ..SNIP... on ..SNIP... (cost=0.43..175.89 rows=29 width=4)
Index Cond: (user_id = 6)
Filter: ..SNIP...
我可以使用.only('id') 修改ORM 表达式以仅选择一个字段。但是,这不会产生我想要的结果。它对id 进行了不必要的排序。理想情况下,我想做一个.only(None),因为这里不需要任何列。它们只会增加重量。
如果可能,我还想删除 DISTINCT 关键字。不过,我认为如果删除列,它不会增加太多执行时间。
这似乎可以全面完成,因为.exists() 返回一个布尔值。返回的列都没有用于任何内容。它们只会使查询复杂化并降低性能。
【问题讨论】:
-
您使用的是什么版本的 Django,以及导致该查询的代码是什么?当我尝试
User.objects.exists()时,它会运行SELECT (1) AS "a" FROM "auth_user" LIMIT 1,这是我所期望的。 -
我使用的是 Django 1.11.5。我会环顾四周,看看是否有任何自定义代码干扰了这一点并导致选择了额外的列。
-
在我不知道的地方有一个
.distinct()调用应用于我的 QuerySet。这把一切都搞砸了。
标签: sql django django-orm