通过在 postgresql 上索引时间戳列来加快搜索速度?
Faster search by indexing timestamp column on postgresql?
我有一个 PostgreSQL 数据库和一个由事件组成的 table。这些事件有列 end_time,它有一个时间戳类型(没有时区信息)。在我的应用程序中,我经常查询 table,试图 select 将来发生的所有事件。所以基本上我正在做这种 SQL 查询:
SELECT * FROM events WHERE end_time >= ?::timestamp
我目前在 end_time 列上没有索引。我担心一旦我的 table 行大小变大(实际上它已经做了很多),对未来事件的搜索查询会变慢?因为现在数据库搜索必须遍历所有行以选择将来发生(或更准确地说,结束)的行。我以前用过索引,但不能说我是最熟悉的。我想知道通过为它创建默认的 Postgres 索引来索引 end_time 列是否会提高查询的性能?我还没有真正的问题,但我不想等到数据量增加后才出现。因为那时有点晚了,至少终端应用的用户体验下降了。
我想指出,我确实使用了不带时区的时间戳,因为我的应用程序始终采用当地时间,我不需要时区信息。但我听说它可能对索引有影响?此外,我的时间戳目前不受任何限制。所以他们理论上可以从现在到无限的未来。我想知道设置一些约束是否可以使索引更好?活动时间之类的应该在15年之内吧?
另一种选择是,我会将事件移动到另一个 table 过去的事件 (archived_events)。这样 table 事件的大小就不会变得太大。例如,我可以有一个定期执行的 cron 作业。
我还听说 运行ning analyze/explain 到数据库实际上可以提高它的性能?如果是这种情况,我应该多久 运行 一次?
PostgreSQL 版本:12.3
I wonder if indexing the end_time
column [...] would increase the performance of the query?
如果 Postgres 预计只有百分之几或更少符合条件(将来有 end_time
),它将在“索引扫描”或“位图索引扫描”中使用列上的索引。
如果这个估计不太远,它实际上也会提高性能。这就是为什么您应该默认启用 autovacuum
的原因:使列统计信息保持最新。
如果您实际上不需要查询中的所有列 (SELECT *
)(您通常不需要),则仅列出您实际需要的列以使其更快。甚至可能允许“仅索引扫描”。参见:
- Postgres not using index when index scan is much better option
- Are regular VACUUM ANALYZE still recommended under 9.1?
- Postgres Slow Queries - Autovacuum frequency
I wonder if setting some constraints could make the indexing better? Something like the event time should be within 15 year or something?
否。对您的查询没有任何影响。以后的行数是决定因素
I would move events to another table that are in the past (archived_events) ...?
Btree 索引扩展性极佳。这意味着,只要只有几行符合条件,被淘汰的行数就无关紧要。如果您的 table 是 巨大的 (数百万或数十亿行)并且其中大部分在过去,partial index可能会更好,主要是由于索引大小和索引维护成本的减少。
特殊困难:“现在”是一个动态值。索引定义需要 immutable 值。解决方法是选择一个任意的“现在”来切断大部分行。类似于:
CREATE INDEX ON events(end_time) WHERE end_time > '2021-01-30';
现代 Postgres 足够聪明,可以理解它可以为未来的日期使用索引。 旧版本可能需要一个冗余的WHERE
子句来理解部分索引是适用的:
SELECT * FROM events
WHERE end_time >= ?::timestamp
AND end_time > '2021-01-30'; -- match index
索引的有用性会随着时间的推移而降低,这也取决于行流失。您可能会不时重新创建索引以切断更多行。
另外,不要让类型名称 timestamp with time zone
误导您。它不存储时区信息。它通常是最佳选择。参见:
- Ignoring time zones altogether in Rails and PostgreSQL
我有一个 PostgreSQL 数据库和一个由事件组成的 table。这些事件有列 end_time,它有一个时间戳类型(没有时区信息)。在我的应用程序中,我经常查询 table,试图 select 将来发生的所有事件。所以基本上我正在做这种 SQL 查询:
SELECT * FROM events WHERE end_time >= ?::timestamp
我目前在 end_time 列上没有索引。我担心一旦我的 table 行大小变大(实际上它已经做了很多),对未来事件的搜索查询会变慢?因为现在数据库搜索必须遍历所有行以选择将来发生(或更准确地说,结束)的行。我以前用过索引,但不能说我是最熟悉的。我想知道通过为它创建默认的 Postgres 索引来索引 end_time 列是否会提高查询的性能?我还没有真正的问题,但我不想等到数据量增加后才出现。因为那时有点晚了,至少终端应用的用户体验下降了。
我想指出,我确实使用了不带时区的时间戳,因为我的应用程序始终采用当地时间,我不需要时区信息。但我听说它可能对索引有影响?此外,我的时间戳目前不受任何限制。所以他们理论上可以从现在到无限的未来。我想知道设置一些约束是否可以使索引更好?活动时间之类的应该在15年之内吧?
另一种选择是,我会将事件移动到另一个 table 过去的事件 (archived_events)。这样 table 事件的大小就不会变得太大。例如,我可以有一个定期执行的 cron 作业。
我还听说 运行ning analyze/explain 到数据库实际上可以提高它的性能?如果是这种情况,我应该多久 运行 一次?
PostgreSQL 版本:12.3
I wonder if indexing the
end_time
column [...] would increase the performance of the query?
如果 Postgres 预计只有百分之几或更少符合条件(将来有 end_time
),它将在“索引扫描”或“位图索引扫描”中使用列上的索引。
如果这个估计不太远,它实际上也会提高性能。这就是为什么您应该默认启用 autovacuum
的原因:使列统计信息保持最新。
如果您实际上不需要查询中的所有列 (SELECT *
)(您通常不需要),则仅列出您实际需要的列以使其更快。甚至可能允许“仅索引扫描”。参见:
- Postgres not using index when index scan is much better option
- Are regular VACUUM ANALYZE still recommended under 9.1?
- Postgres Slow Queries - Autovacuum frequency
I wonder if setting some constraints could make the indexing better? Something like the event time should be within 15 year or something?
否。对您的查询没有任何影响。以后的行数是决定因素
I would move events to another table that are in the past (archived_events) ...?
Btree 索引扩展性极佳。这意味着,只要只有几行符合条件,被淘汰的行数就无关紧要。如果您的 table 是 巨大的 (数百万或数十亿行)并且其中大部分在过去,partial index可能会更好,主要是由于索引大小和索引维护成本的减少。
特殊困难:“现在”是一个动态值。索引定义需要 immutable 值。解决方法是选择一个任意的“现在”来切断大部分行。类似于:
CREATE INDEX ON events(end_time) WHERE end_time > '2021-01-30';
现代 Postgres 足够聪明,可以理解它可以为未来的日期使用索引。 旧版本可能需要一个冗余的WHERE
子句来理解部分索引是适用的:
SELECT * FROM events
WHERE end_time >= ?::timestamp
AND end_time > '2021-01-30'; -- match index
索引的有用性会随着时间的推移而降低,这也取决于行流失。您可能会不时重新创建索引以切断更多行。
另外,不要让类型名称 timestamp with time zone
误导您。它不存储时区信息。它通常是最佳选择。参见:
- Ignoring time zones altogether in Rails and PostgreSQL