为啥 postgresql 不使用我的 group by 聚合索引?
Posted
技术标签:
【中文标题】为啥 postgresql 不使用我的 group by 聚合索引?【英文标题】:Why isn't postgresql using an index with my group by aggregate?为什么 postgresql 不使用我的 group by 聚合索引? 【发布时间】:2022-01-15 21:42:24 【问题描述】:我在 postgresql 数据库中有一个启用了 timescaledb 扩展的表,如下所示:
+------------+--------------------------+-------------+
| Column | Type | Modifiers |
|------------+--------------------------+-------------|
| time | timestamp with time zone | not null |
| value | double precision | not null |
| being | metric_being | not null |
| device | integer | not null |
+------------+--------------------------+-------------+
还有一个索引在桌子上:
"metrics_device_time_idx" btree (device, "time" DESC)
但是当我使用 Group By 查询表时:
explain select max(time), device from metrics group by device;
它不使用索引:
+----------------------------------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------+
| QUERY PLAN |
|-------------------------------------------------------------------------------------------------------------------|
| Finalize GroupAggregate (cost=104577.41..104588.61 rows=22 width=12) |
| Group Key: _hyper_9_95_chunk.device |
| -> Gather Merge (cost=104577.41..104587.95 rows=88 width=12) |
| Workers Planned: 4 |
| -> Sort (cost=103577.35..103577.41 rows=22 width=12) |
| Sort Key: _hyper_9_95_chunk.device |
| -> Partial HashAggregate (cost=103576.64..103576.86 rows=22 width=12) |
| Group Key: _hyper_9_95_chunk.device |
| -> Parallel Append (cost=0.00..95035.06 rows=1708317 width=12) |
| -> Parallel Seq Scan on _hyper_9_95_chunk (cost=0.00..44602.70 rows=1122370 width=12) |
| -> Parallel Seq Scan on _hyper_9_92_chunk (cost=0.00..24807.61 rows=756061 width=12) |
+-------------------------------------------------------------------------------------------------------------------+
最后开始有点慢。另一方面,真正快 10 倍的是
select max(time), 29 from metrics where device = 29
union
select max(time), 30 from metrics where device = 30
union
...
为什么会这样?我可以使用group by
更改我的索引或查询以加快查询速度吗?为什么union
这么快?
【问题讨论】:
你是如何在 timescaledb 中对表进行分区的? 没有空间分区,超表创建时使用:select create_hypertable ('metrics', 'time');
那么,一个设备的时间是跨多个时间序列交错的?对于您的查询,这似乎不是最佳选择。
【参考方案1】:
正如@Pavel Stehule 在他的回答中提到的,Postgres 没有实现索引跳过扫描,这是优化这些类型的查询所必需的。 Timescaledb 认识到这些类型的查询在时间序列分析中确实很有帮助,因此他们自己实现了索引跳过扫描。它存在于他们从 2.2.1 版本开始的扩展中,请参阅他们关于它的博客文章 here。
将扩展升级到 >= 2.2.1 后,可以重写查询以使用索引跳过扫描:
select distinct on (device) device, time from metrics order by device, time desc
然后使用他们的索引跳过扫描实现,在我的例子中,查询速度提高了大约 100 倍。
【讨论】:
【参考方案2】:Postgres 不能在这种情况下使用索引。优化器现在不支持这一点。你可以找到一些关于这个的信息 - 有一个名为“索引跳过扫描”的补丁,但这项工作还没有完成。你可以使用一些workarounds。
【讨论】:
有没有办法使用 CTE 复制group by
,如链接中所述?我试图得到一个包含两列的结果集,time
和 device
。
当然是。但我想念你使用时间刻度 - 它具有增强的优化器,所以也许会有其他更好的解决方案。 Timescaledb 和类似系统更敏感,您应该更仔细地遵循文档和模式。以上是关于为啥 postgresql 不使用我的 group by 聚合索引?的主要内容,如果未能解决你的问题,请参考以下文章
带有注释的Django查询集,为啥将GROUP BY应用于所有字段?
为啥我的 PostgreSQL 数组索引没有被使用(Rails 4)?
PostgreSQL GROUP BY LOWER() 不工作