【问题标题】:Sequential scan over index scan used on truncated DATE field对截断的 DATE 字段使用的索引扫描进行顺序扫描
【发布时间】:2020-12-22 08:11:28
【问题描述】:

我使用 PostgreSQL,并且我有一个名为 table 的表。 此表包含一个名为 created_at 的列(data_typetimestamptz),它使用 BTREE 进行索引。

我想计算一段时间内按created_at::date 分组的行数(按from_dateend_date 过滤)。

我运行以下查询(结果符合预期):

SELECT ("table"."created_at" AT TIME ZONE 'UTC')::date AS "date",
       COUNT("table"."id") AS "count"
FROM "table"
WHERE ("table"."created_at" >= '2018-08-05T00:00:00+00:00'::timestamptz AND "table"."created_at" <= '2020-09-05T00:00:00+00:00'::timestamptz)
GROUP BY ("table"."created_at" AT TIME ZONE 'UTC')::date
ORDER BY "date" ASC

此查询需要很长时间才能运行(超过 200 万行),在查看查询计划时,我注意到有大量 Seq Scan

GroupAggregate  (cost=538741.06..605206.42 rows=2954016 width=12) (actual time=3866.460..5077.054 rows=559 loops=1)
  Group Key: ((timezone('UTC'::text, created_at))::date)
  ->  Sort  (cost=538741.06..546126.10 rows=2954016 width=8) (actual time=3866.414..4413.922 rows=2954016 loops=1)
        Sort Key: ((timezone('UTC'::text, created_at))::date)
        Sort Method: external merge  Disk: 52056kB
        ->  Seq Scan on table  (cost=0.00..140489.32 rows=2954016 width=8) (actual time=0.070..2194.108 rows=2954016 loops=1)
              Filter: ((created_at >= '2018-08-05 00:00:00+00'::timestamp with time zone) AND (created_at <= '2020-09-05 00:00:00+00'::timestamp with time zone))
Planning time: 1.018 ms
Execution time: 5094.280 ms

我想了解以下内容:

  1. 查询中应该改进的地方(如果有的话)
  2. 表结构有哪些需要改进的地方(如果有的话)
  3. 使用的索引类型 (BTREE) 是否适合此类查询?

【问题讨论】:

    标签: sql postgresql query-performance


    【解决方案1】:

    看来您的 WHERE 条件实际上并未过滤掉任何行,因此表中的所有行都已处理。在这种情况下,使用 Seq Scan 是检索数据的最有效方式。如果您将时间范围缩小,以便只检索表的一小部分行,则优化器应使用索引。

    Seq Scan 只占用查询时间的一半,另一半花费在 GROUP BY(或对其进行排序)。如果您增加work_mem,至少排序/分组应该更快(更多work_mem)排序可能会被哈希聚合替换。

    假设id 定义为not null,那么使用count(*) 而不是count(id) 也会使查询更快。一方面是因为 count 函数中不再需要“空检查”。但更重要的是,因为 Postgres 可能只进行索引扫描,因为只需要直接在索引中可用的 created_at 列。如果这没有切换到仅索引扫描,您可能需要运行 vacuum analyze the_table; 来更新可见性映射。

    【讨论】:

    • 感谢@a_horse_with_no_name 的明确解释。对于第一点,是的,你是对的。对于 GROUP BY,我会尝试增加和调整 work_mem。最后一点也很有帮助(影响较小)。
    猜你喜欢
    • 2021-06-23
    • 2021-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-15
    • 2018-02-18
    • 2022-12-05
    相关资源
    最近更新 更多