postgres如何调试为什么计划时间太长?

时间:2017-07-12 23:51:53

标签: postgresql

版本 - postgres 9.6。

我在question过去并没有那么清楚,有人已经在那里回答,所以我认为最好发布一个更清晰信息的新问题,并对我的问题更具体。

尝试使用维度表连接事件表。 事件表是一个每日分区(3k子)表,带有检查约束。事件表有72列(我怀疑这是问题)。

我简化了查询以便演示问题(在实践中范围更广,我从两个表中查询字段)。

你可以看到,对于这个简单的查询 - 计划需要大约10秒钟(我的问题是关于计划时间而不是执行时间)。 如果我直接查询子表(请不要建议在范围内的所有子项上使用union)查询计划是几毫秒。

explain analyze select campaign_id ,  spent   as spent from events_daily r left join report_campaigns c on r.campaign_id = c.c_id  where  date >= '20170720' and date < '20170721' ;
                                                                      QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop Left Join  (cost=0.29..28.88 rows=2 width=26) (actual time=0.021..0.021 rows=0 loops=1)
   ->  Append  (cost=0.00..12.25 rows=2 width=26) (actual time=0.003..0.003 rows=0 loops=1)
         ->  Seq Scan on events_daily r  (cost=0.00..0.00 rows=1 width=26) (actual time=0.002..0.002 rows=0 loops=1)
               Filter: ((date >= '2017-07-20 00:00:00'::timestamp without time zone) AND (date < '2017-07-21 00:00:00'::timestamp without time zone))
         ->  Seq Scan on events_daily_20170720 r_1  (cost=0.00..12.25 rows=1 width=26) (actual time=0.000..0.000 rows=0 loops=1)
               Filter: ((date >= '2017-07-20 00:00:00'::timestamp without time zone) AND (date < '2017-07-21 00:00:00'::timestamp without time zone))
   ->  Index Only Scan using report_campaigns_campaign_idx on report_campaigns c  (cost=0.29..8.31 rows=1 width=8) (never executed)
         Index Cond: (c_id = r.campaign_id)
         Heap Fetches: 0
 Planning time: 8393.337 ms
 Execution time: 0.132 ms
(11 rows)

explain analyze select campaign_id ,  spent   as spent from events_daily_20170720 r left join report_campaigns c on r.campaign_id = c.c_id  where  date >= '20170720' and date < '20170721' ;
                                                                   QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop Left Join  (cost=0.29..20.57 rows=1 width=26) (actual time=0.008..0.008 rows=0 loops=1)
   ->  Seq Scan on events_daily_20170720 r  (cost=0.00..12.25 rows=1 width=26) (actual time=0.007..0.007 rows=0 loops=1)
         Filter: ((date >= '2017-07-20 00:00:00'::timestamp without time zone) AND (date < '2017-07-21 00:00:00'::timestamp without time zone))
   ->  Index Only Scan using report_campaigns_campaign_idx on report_campaigns c  (cost=0.29..8.31 rows=1 width=8) (never executed)
         Index Cond: (c_id = r.campaign_id)
         Heap Fetches: 0
 Planning time: 0.242 ms
 Execution time: 0.059 ms


\d events_daily_20170720
 date                      | timestamp without time zone |
Check constraints:
    "events_daily_20170720_date_check" CHECK (date >= '2017-07-20 00:00:00'::timestamp without time zone AND date < '2017-07-21 00:00:00'::timestamp without time zone)
Inherits: events_daily

show constraint_exclusion;
 constraint_exclusion
----------------------
 on

当运行ltrace时,它似乎在每个字段上运行了数千次(暗示它在该计划的所有patitions表上运行):

strlen("process")                                                                                                                                                    = 7
memcpy(0x0b7aac10, "process", 8)                                                                                                                                     = 0x0b7aac10
strlen("channel")                                                                                                                                                    = 7
memcpy(0x0b7aac68, "channel", 8)                                                                                                                                     = 0x0b7aac68
strlen("deleted")                                                                                                                                                    = 7
memcpy(0x0b7aacc0, "deleted", 8)                                                                                                                                     = 0x0b7aacc0
strlen("old_spent")                                                                                                                                                  = 9
memcpy(0x0b7aad18, "old_spent", 10)

1 个答案:

答案 0 :(得分:2)

问题是你的分区太多了。

正如the documentation警告:

  

在约束排除期间检查主表的所有分区上的所有约束,   如此大量的分区可能会大大增加查询计划时间。   使用这些技术进行分区可以很好地处理大约一百个分区;   不要尝试使用数千个分区。

您应该尝试通过为每个分区使用更长的时间间隔来减少分区数。

或者,您可以尝试更改应用程序代码,以便在可能的情况下直接访问正确的分区,但这可能会很困难,并且会消除分区带来的许多优势。