【发布时间】:2020-02-14 22:31:15
【问题描述】:
我有两张 Postgres 表:一张普通表(20M 行)和一张物化视图(2M 行)。两个表的“时间”列都有索引。在这两个表上,我正在运行一个在日期范围内聚合的查询。当我在普通表上运行查询时,Postgres 使用索引扫描,大约需要 1 秒。但是,在物化视图上,Postgres 使用 Bitmap Index Scan,大约需要 7 秒。我不确定为什么这里没有使用正常的索引扫描。
两张表大致相似;物化视图有 3 个额外的列(2 个浮点数和一个布尔值)。这两个表的id 列和time 列都有索引;在普通表中,id 列是主键。这两个表都是VACUUM ANALYZEd。
查询如下:
SELECT count(*) as post_count,
sum(CASE WHEN in_reply_to_post_id IS NULL THEN 0 ELSE 1 END) as replies,
date_trunc('hour', time) as time_interval
FROM posts_enriched_materialized_2_weeks
WHERE time >= '2019-10-10' AND time < '2019-10-11'
GROUP BY time_interval;
EXPLAIN ANALYZE在物化视图上的结果如下:
GroupAggregate (cost=264262.43..268387.60 rows=158191 width=32) (actual time=7794.743..7893.961 rows=24 loops=1)
Group Key: (date_trunc('hour'::text, "time"))
-> Sort (cost=264262.43..264691.99 rows=171822 width=46) (actual time=7790.080..7838.184 rows=175691 loops=1)
Sort Key: (date_trunc('hour'::text, "time"))
Sort Method: external merge Disk: 5464kB
-> Bitmap Heap Scan on posts_enriched_materialized_2_weeks (cost=4057.61..244033.53 rows=171822 width=46) (actual time=21.184..7672.166 rows=175691 loops=1)
Recheck Cond: (("time" >= '2019-10-10 00:00:00'::timestamp without time zone) AND ("time" < '2019-10-11 00:00:00'::timestamp without time zone))
Heap Blocks: exact=17420
-> Bitmap Index Scan on posts_enriched_materialized_2_weeks_time_index (cost=0.00..4014.65 rows=171822 width=0) (actual time=18.551..18.551 rows=175691 loops=1)
Index Cond: (("time" >= '2019-10-10 00:00:00'::timestamp without time zone) AND ("time" < '2019-10-11 00:00:00'::timestamp without time zone))
Planning time: 0.106 ms
Execution time: 7894.874 ms
编辑:非MV表上EXPLAIN ANALYZE的结果如下:
GroupAggregate (cost=193490.77..197635.89 rows=150641 width=32) (actual time=1168.018..1267.225 rows=24 loops=1)
Group Key: (date_trunc('hour'::text, "time"))
-> Sort (cost=193490.77..193943.19 rows=180969 width=46) (actual time=1163.293..1210.887 rows=175701 loops=1)
Sort Key: (date_trunc('hour'::text, "time"))
Sort Method: external merge Disk: 5472kB
-> Index Scan using posts_time_index on tweets (cost=0.44..172118.80 rows=180969 width=46) (actual time=0.900..1065.469 rows=175701 loops=1)
Index Cond: (("time" >= '2019-10-10 00:00:00'::timestamp without time zone) AND ("time" < '2019-10-11 00:00:00'::timestamp without time zone))
Planning time: 0.514 ms
Execution time: 1268.219 ms
下面是 cmets 中请求的每个表的 time 列的相关性。我不完全知道这个值指的是什么,但它看起来非常相关:
posts 0.8844374
posts_enriched_materialized_2_weeks 0.09846322
【问题讨论】:
-
Bitmap Index/Heap Scan并不是减慢 MV 查询速度的原因。相反,花费大部分时间的是external merge Disk: 5464kB。你的work_mem设置是什么?也许您可以将其增加到至少 6MB? -
真的吗?
actual time的排序是 7838 毫秒,Bitmap Index Scan只需要 18 毫秒 -
请在另一张桌子上出示解释计划。
-
@richyen 实际上排序占用的时间很少。需要时间的是位图堆扫描(远远超过 90%)。为排序给出的时间包括排序“之前”步骤的时间,因此排序本身只需要大约 7838 - 7672 = 166 毫秒。
-
旁白:将
sum(CASE WHEN in_reply_to_post_id IS NULL THEN 0 ELSE 1 END)替换为等效的count(in_reply_to_post_id)。更简单,可能更快。
标签: postgresql