我正在尝试优化由Django ORM生成的慢查询。这是一个多对多查询。运行需要1分钟以上。
这些表有大量数据,但它们并不大(sp_article中有400k行,sp_article_categories中有300k行)
#categories.article_set.filter(post_count__lte=50)
EXPLAIN ANALYZE SELECT *
FROM "sp_article"
INNER JOIN "sp_article_categories" ON ("sp_article"."id" = "sp_article_categories"."article_id")
WHERE ("sp_article_categories"."category_id" = 1081
AND "sp_article"."post_count" <= 50 )
Nested Loop (cost=0.00..6029.01 rows=656 width=741) (actual time=0.472..25.724 rows=1266 loops=1)
-> Index Scan using sp_article_categories_category_id on sp_article_categories (cost=0.00..848.82 rows=656 width=12) (actual time=0.015..1.305 rows=1408 loops=1)
Index Cond: (category_id = 1081)
-> Index Scan using sp_article_pkey on sp_article (cost=0.00..7.88 rows=1 width=729) (actual time=0.014..0.015 rows=1 loops=1408)
Index Cond: (sp_article.id = sp_article_categories.article_id)
Filter: (sp_article.post_count <= 50)
Total runtime: 26.536 ms
我有一个索引:
sp_article_categories.article_id (type: btree)
sp_article_categories.category_id
sp_article.post_count (type: btree)
有关如何调整此内容以快速获取查询的任何建议吗?
谢谢!
答案 0 :(得分:1)
您在此提供了重要信息 - 解释分析。虽然没有显示1秒的运行时间,但它显示的是20毫秒。所以 - 这不是正在运行的查询,或者问题出在其他地方。
解释分析和实际应用之间的唯一区别是实际上没有返回结果。你需要大量数据才能将速度减慢到1秒。
其他建议都不合适,因为他们忽略了查询不慢的事实。你有相关的索引(连接的两边都使用了索引扫描),并且规划器完全能够首先对类别表进行过滤(这就是拥有一半体面的查询规划器的全部意义)。
所以 - 你首先需要弄清楚究竟什么是慢......
答案 1 :(得分:0)
在sp_article_categories.category_id
答案 2 :(得分:0)
从纯SQL角度来看,如果基表中的行数较少,则连接会更有效,并且在该表连接到另一个表之前会对该表执行WHERE条件。
那么看看你是否可以让Django先从类别中选择,然后在加入文章表之前过滤category_id。
伪代码如下:
SELECT * FROM categories c
INNER JOIN articles a
ON c.category_id = 1081
AND c.category_id = a.category_id
像史蒂文建议的那样在category_id
上加上一个索引。
答案 3 :(得分:0)
您也可以使用字段名称*。
从......中选择[字段]
答案 4 :(得分:0)
我假设您已对数据库运行分析以获取新的统计信息。
似乎sp_article.id和sp_article_categories.article_id之间的连接成本很高。什么数据类型是文章ID,数字?如果不是,你应该考虑将它变成数字 - 整数或bigint,无论你需要什么套件。根据我的经验,它可以在性能上产生很大的不同。希望它有所帮助。
干杯! //约翰