postgresql - 通过在 postgresql 上索引时间戳列来加快搜索速度?

标签 postgresql indexing timestamp postgresql-performance

我有一个 PostgreSQL 数据库和一个包含事件的表。这些事件具有 end_time 列,该列具有时间戳类型(没有时区信息)。在我的应用程序中,我经常查询表,尝试选择将来发生的所有事件。所以基本上我正在做这种 SQL 查询:

SELECT * FROM events WHERE end_time >= ?::timestamp

我目前在 end_time 列上没有索引。我担心一旦我的表行大小变大(实际上它已经做了很多),对 future 事件的搜索查询会变得更慢?因为现在数据库搜索必须遍历所有行来选择将来发生的行(或更准确地说,结束)。我以前使用过索引,但不能说我是最熟悉它们的。我想知道通过创建默认的 Postgres 索引来索引 end_time 列是否会提高查询的性能?我还没有遇到真正的问题,但我不想等到数据量增加后才出现。因为那时就有点太晚了,至少最终应用程序的用户体验已经下降了。

我想指出,我确实使用不带时区的时间戳,因为我的应用程序始终假定本地时间,并且我不需要时区信息。但我听说它可能会对索引产生影响?另外,我的时间戳目前不受任何限制。所以理论上它们可以是从现在到无限的 future 。我想知道设置一些约束是否可以使索引更好?像事件时间应该在 15 年之内之类的吗?

另一种选择是我将事件移动到过去的另一个表(archived_events)。这样赛事的 table 规模就不会太大。例如,我可以有一个定期执行此操作的 cron 作业。

我还听说对数据库运行分析/解释实际上可以提高其性能?如果是这种情况,我应该多久运行一次?

PostgreSQL 版本:12.3

最佳答案

I wonder if indexing the end_time column [...] would increase the performance of the query?

如果 Postgres 预计只有百分之几或更少符合条件(将来有 end_time),它将在“索引扫描”或“位图索引扫描”中使用列上的索引。

如果这个估计不是太离谱,它实际上也会提高性能。这就是为什么您应该默认启用 autovacuum:以使列统计信息保持最新。

如果您实际上不需要查询 (SELECT *) 中的所有列(通常不需要),则只需列出您实际需要的列,以提高速度。甚至可能允许“仅索引扫描”。请参阅:

I wonder if setting some constraints could make the indexing better? Something like the event time should be within 15 year or something?

不会。对您的查询没有任何影响。 future 的行数是决定因素。

I would move events to another table that are in the past (archived_events) ...?

Btree 索引具有出色的扩展性。这意味着,只要只有少数行符合条件,消除的行数就几乎不重要。如果您的表巨大(数百万或数十亿行)并且其中大部分都是过去的,则 partial index可能会更好,主要是由于索引大小和索引维护成本的减少。

特殊困难:“现在”是一个动态值。索引定义需要不可变值。解决方法是选择任意一个“现在”来切断大部分行。像这样的东西:

CREATE INDEX ON events(end_time) WHERE end_time > '2021-01-30';

现代 Postgres 足够聪明,知道它可以使用 future 日期的索引。 旧版本可能需要冗余的WHERE子句才能使其了解部分索引适用:

SELECT * FROM events
WHERE  end_time >= ?::timestamp
AND    end_time > '2021-01-30';  -- match index

索引的有用性会随着时间的推移而下降,这也取决于行的变动。您可能会不时重新创建索引以切断更多行。


另外,不要让类型名称 timestamp with time zone 误导您。它不存储时区信息。它通常是最好的选择。请参阅:

关于postgresql - 通过在 postgresql 上索引时间戳列来加快搜索速度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65968537/

相关文章:

ruby-on-rails - Cloud9 "fe_sendauth: no password supplied"中的 postgresql 错误

postgresql - 运算符不存在 : geography <-> geography

mysql - 如何使用自定义字段选择索引mysql表

java - 如何在 Java 或 SQL 中将 ISO DATE 转换为时间戳?

sql - PostgreSQL - GROUP BY 时间戳值?

postgresql - 在 Postgis 中,如何从空间表和相关(非空间)表之间的一对多关系构建 Geojson

postgresql - 将点类型数据保存到 pg 服务器

sql - 死锁使用自引用外键

sql - 在表变量上创建索引

c++时间戳到人类可读的日期时间函数