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 在按日期索引的时间戳字段上按日期搜索性能不佳的主要内容,如果未能解决你的问题,请参考以下文章
如何将 bigint 字段格式化为 Postgresql 中的日期?
PostgreSQL 获取两个日期时间/时间戳之间的随机日期时间/时间戳