Postgresql甚至用索引缓慢加入?

时间:2013-09-06 05:47:17

标签: django postgresql

我试图弄清楚为什么特定的SQL查询在postgres上运行缓慢。没有太多解释,这里是查询的EXPLAIN ANALYZE:

explain analyze SELECT "addressbooks_address"."id", "addressbooks_address"."name" FROM "addressbooks_recipientaddress" INNER JOIN"addressbooks_address" ON ("addressbooks_recipientaddress"."address_ptr_id" = "addressbooks_address"."id") ORDER BY "addressbooks_recipientaddress"."address_ptr_id" ASC LIMIT 1000 OFFSET 378000;

QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=40139.55..40245.42 rows=1000 width=21) (actual time=720.444..721.958 rows=1000 loops=1)
   ->  Merge Join  (cost=121.88..67152.43 rows=633159 width=21) (actual time=0.028..698.069 rows=379000 loops=1)
     Merge Cond: (addressbooks_recipientaddress.address_ptr_id = addressbooks_address.id)
     ->  Index Scan using addressbooks_recipientaddress_pkey on addressbooks_recipientaddress  (cost=0.00..19258.72 rows=633159 width=4) (actual time=0.012..189.480 rows=379000 loops=1)
     ->  Index Scan using addressbooks_address_pkey on addressbooks_address  (cost=0.00..38291.65 rows=675743 width=17) (actual time=0.011..227.094 rows=388264 loops=1)
Total runtime: 722.092 ms

该查询是由django生成的,但我在将其发布之前对其进行了简化。但问题仍然存在。我有addressbooks_address.id和addressbooks_recipientaddress.address_ptr_id的索引,如解释所示。

有什么想法吗?

1 个答案:

答案 0 :(得分:2)

  

LIMIT 1000 OFFSET 378000

快速查看你在做什么;你正在产生一个相当大的连接,然后将绝大部分连接扔掉。

如果可能,请尝试使用感兴趣的行的主键进行分页,而不是使用OFFSET。记住addressbooks_address.id以及addressbooks_recipientaddress的关键字来自先前结果中的最后一个元组,并使用WHERE子句,如:

WHERE "addressbooks_recipientaddress"."id" > $1
  AND "addressbooks_address"."id" > $2

而不是OFFSET。这样你的索引扫描就可以跳到那些记录,而不是浪费所有的时间来产生结果扔掉。

如果您的框架无法做到这一点,那就是我不喜欢查询生成器框架的原因。