Postgres 查询计划对于增加时间戳范围的查询有很大不同

Posted

技术标签:

【中文标题】Postgres 查询计划对于增加时间戳范围的查询有很大不同【英文标题】:Postgres Query Plan hugely differs for query with increased timetamp range 【发布时间】:2021-04-19 12:07:32 【问题描述】:

嘿,postgres 专家。 我们的一张桌子面临着一种奇怪的行为。在增加查询时间戳范围的同时,会出现查询时间突然增加约 5 倍的临界点。

我们正在查看的表格:

                   Table "measurements.hourly_measurement_recordings"
        Column         |              Type              | Collation | Nullable | Default 
-----------------------+--------------------------------+-----------+----------+---------
 dimension_identifier  | integer                        |           | not null | 
 occasion_identifier   | integer                        |           | not null | 
 items_identifier      | bit(64)                        |           | not null | 
 beginning_of_timeslot | timestamp(0) without time zone |           | not null | 
 dumped_weight         | integer                        |           | not null | 
Indexes:
    "hourly_measurement_recordings_kind_identifier_type_identifier_p" UNIQUE, btree (occasion_identifier, dimension_identifier, items_identifier, beginning_of_timeslot)
    "hourly_measurement_recordings_kind_identifier_type_identifier_b" btree (occasion_identifier, dimension_identifier, beginning_of_timeslot)

第一个查询+计划: https://explain.depesz.com/s/LyzL

第二次查询+计划: https://explain.depesz.com/s/ZCvZ

这两个查询之间的唯一区别是增加了时间戳范围:

'2021-03-15 23:00:00Z', '2021-04-19 21:00:00Z'

'2021-03-14 23:00:00Z', '2021-04-19 21:00:00Z'

如您所见,从 Parallel Bitmap Heap ScanParallel Seq Scan 的转换增加了查询时间。

这里是我使用的数据库的一些规格:

PostgreSQL v13.1 在具有 2 个 vCPU、4GB RAM、通用 SSD (40GB) 的 AWS db.t3.medium 上运行

我对数据库配置不是很熟悉,所以我真的不知道哪些参数可能对您有用 - 如果有更多相关信息可以分享,请告诉我。

谢谢你, 尼克

【问题讨论】:

您可能想要更改 work_mem,这两个查询都使用外部合并进行排序。尝试类似 100MB:SET work_mem TO '100MB';然后再试一次。 我也会尝试这样的索引,从 begin_of_timeslot 开始:"hourly_measurement_recordings_kind_identifier_type_identifier_c" btree (beginning_of_timeslot , scene_identifier, dimension_identifier); tyvm - 我会尝试两个 第一个问题:查询是:WHERE beginning_of_timeslot WHERE (dimension_identifier and occasion_identifier) OR ... 那么索引顺序是[beginnig_of_timeslot, dimension_identifier, occasion_identifier] 还是[beginning_of_timeslot, occasion_identifier, dimension_identifier] 哪一列的唯一值最多?那应该是第一位的。 【参考方案1】:

可能会出现一个临界点,即 seq 扫描实际上变得比位图扫描更快。还有一点,规划者认为 seq 扫描会变得更快。这些几乎永远不会完全对齐,因为计划者永远不会完美。所以,这并不奇怪。

值得注意的是,位图扫描在内存中发现了它需要的每个块。很难相信这是一个现实的情况。这可能是因为您重复运行完全相同的查询。如果您查询一组不同的参数,因此并非所有数据都已在内存中怎么办?

看起来您正在使用或多或少的计划器默认设置运行。但是对于 SSD 磁盘,random_page_cost 的默认设置通常太高。将其更改为 1.1 而不是 4 可能更合适。仅这一点就可能将切入点向适当的方向移动,尽管我不知道它是否会充分移动。

您对 max_parallel_workers_per_gather 的设置似乎最后是 2。但是对于 t3.medium 实例,这应该是 0 或最多 1。(另外,如果您关心的话,您不应该首先使用 t3 实例性能,因为它们的性能在设计上是不稳定的)。此外,您似乎正在使用可突发的 IO 类。但是一旦你用尽了 IO 信用,性能就会一落千丈,这在 seq 扫描中似乎已经发生了。

【讨论】:

谢谢您-我会考虑您的建议。我为beginning_of_timeslot 列(没有多列)添加了一个索引,它再次将查询计划从bitmap scan 更改为parallel index scan,这似乎产生了很好的影响:explain.depesz.com/s/SFHd 你是绝对正确的——我运行了同样的多次查询并使用不同的时间范围会导致更长的查询时间,但使用相同的查询计划。 t3 实例的使用目前与成本相关——数据很少被查询,但有时是大块的,并且它的插入与 t3 配合得很好。

以上是关于Postgres 查询计划对于增加时间戳范围的查询有很大不同的主要内容,如果未能解决你的问题,请参考以下文章

范围 COUNT 查询基于 Hibernate 中纪元时间戳的 DATE

Postgres 时间戳

按时间戳分钟在 postgres 中查询

修改 Postgres 9.0 查询计划

在 postgres 中运行时查询计划更改

Postgres 不同的查询计划 Prod/QA