PostgreSQL 在按日期索引的时间戳字段上按日期搜索性能不佳

Posted

技术标签:

【中文标题】PostgreSQL 在按日期索引的时间戳字段上按日期搜索性能不佳【英文标题】:PostgreSQL poor performance searching by date on timestamp field indexed by date 【发布时间】:2020-04-23 18:54:46 【问题描述】:

我有一个带有时间戳字段的表。该表有数百万个来自几年的条目,我希望有一个按日期查询。

它没有按日期索引,所以我这样做了:

CREATE INDEX dt_crea_day_idx
ON my_table (date(dt_crea at TIME ZONE 'UTC'));

之后,下一个查询所用的时间与索引之前的时间相同:

SELECT dt_crea::date as dt_custom, field1, field2
FROM my_table 
WHERE field1='some_value' 
AND    dt_crea::date = '2020-04-23'
ORDER BY dt_custom desc, field2

如何按日期提高此类查询的性能?

编辑:分析 pifor 询问:

Sort  (cost=9616582.37..9616585.03 rows=1064 width=27) (actual time=290355.874..290355.906 rows=670 loops=1)
  Sort Key: field2
  Sort Method: quicksort  Memory: 77kB
  ->  Seq Scan on my_table  (cost=0.00..9616528.88 rows=1064 width=27) (actual time=72308.452..290355.232 rows=670 loops=1)
        Filter: (((field1)::text = 'some_value'::text) AND ((dt_crea)::date = '2020-04-23'::date))
        Rows Removed by Filter: 255195339
Planning time: 0.086 ms
Execution time: 290355.951 ms

【问题讨论】:

dt_crea 的确切数据类型是什么?你跑ANALYZE my_table了吗?请发布EXPLAIN ANALYZE <your query>的输出 你的 where 条件必须使用 exactly 与索引相同的表达式,例如and date(dt_crea at TIME ZONE 'UTC') = ... @a_horse_with_no_name 成功了!也许我误解了一些概念。我希望将字段索引为日期后,我如何使用日期并不重要。最初我试图索引 ((dt_crea::date)) 但它抛出一个错误说:错误:索引表达式中的函数必须标记为 IMMUTABLE。你认为这是最好的近似吗?按 (date(dt_crea at TIME ZONE 'UTC')) 索引并按 (date(dt_crea at TIME ZONE 'UTC')) 搜索? 【参考方案1】:

您的查询必须与您的索引匹配,而您的不匹配。您无法使用 ::date 查询索引,原因与您不允许使用该表达式创建索引的原因相同。

如果您希望使用此策略,则需要更改查询以匹配索引,例如:

SELECT dt_crea::date as dt_custom, field1, field2
FROM my_table 
WHERE field1='some_value' 
AND    date(dt_crea at TIME ZONE 'UTC') = '2020-04-23'
ORDER BY dt_custom desc, field2

【讨论】:

【参考方案2】:

我会在列上创建一个常规索引:

CREATE INDEX dt_crea_day_idx ON my_table (dt_crea);

该索引将更加通用,但您需要稍微更改查询,以便 Postgres 可以使用该索引:

SELECT dt_crea::date as dt_custom, field1, field2
FROM my_table 
WHERE field1='some_value' 
  AND dt_crea >= date '2020-04-23' --<< the day you are looking for
  AND dt_crea < date '2020-04-24' --<< next day
ORDER BY dt_custom desc, field2;

该索引也适用于寻找其他范围,例如特定月份(您的索引不支持):

WHERE dt_crea >= date '2020-04-01'
  AND dt_crea < date '2020-05-01'

对于特定查询(=field1 条件),两列上的索引可能会更好:

CREATE INDEX dt_crea_day_idx ON my_table (field1, dt_crea);

【讨论】:

谢谢。我将第一个答案标记为有效答案,因为它回答了我的具体问题。但我认为您的回答为我最初的问题提供了更好的解决方案。非常感谢。

以上是关于PostgreSQL 在按日期索引的时间戳字段上按日期搜索性能不佳的主要内容,如果未能解决你的问题,请参考以下文章

如何比较 Postgresql 中日期时间字段中的日期?

如何将 bigint 字段格式化为 Postgresql 中的日期?

PostgreSQL 获取两个日期时间/时间戳之间的随机日期时间/时间戳

如何从 SQLite3 和 PostgreSQL 中的时间戳中选择日期

postgresql 将数字转换为日期和格式

将时间戳与查询中的日期名称相等,并在 PostgreSQL 查询中获取结果集 w.r.t 日期名称