版本 - 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)
答案 0 :(得分:2)
问题是你的分区太多了。
正如the documentation警告:
在约束排除期间检查主表的所有分区上的所有约束, 如此大量的分区可能会大大增加查询计划时间。 使用这些技术进行分区可以很好地处理大约一百个分区; 不要尝试使用数千个分区。
您应该尝试通过为每个分区使用更长的时间间隔来减少分区数。
或者,您可以尝试更改应用程序代码,以便在可能的情况下直接访问正确的分区,但这可能会很困难,并且会消除分区带来的许多优势。