Add datetime constraint to a PostgreSQL multi-column partial index
我有一个名为
其中两个列
这是我的问题:
我目前通过运行以下方法在这两列上创建了我的多列索引:
1 | CREATE INDEX CONCURRENTLY some_index_name ON queries_query (user_sid, created) |
但我想进一步限制索引只关心创建日期在过去30天内的查询。 我尝试过以下方法:
1 2 | CREATE INDEX CONCURRENTLY some_index_name ON queries_query (user_sid, created) WHERE created >= NOW() - '30 days'::INTERVAL` |
但这引发了一个异常,说明我的函数必须是不可变的。
我很乐意让这个工作,以便我可以优化我的索引,并削减Postgres需要执行这些重复查询的资源。
您尝试使用
All functions and operators used in an index definition must be"immutable" ...
我在这里看到了两种利用(效率更高)部分索引的方法:
1.使用常数日期的条件的部分索引:
1 2 | CREATE INDEX queries_recent_idx ON queries_query (user_sid, created) WHERE created > '2013-01-07 00:00'::TIMESTAMP; |
假设
- 在Rails和PostgreSQL中完全忽略时区
在流量较低的小时内删除并重新创建该索引,可能每天或每周都有一个cron作业(或者对你来说足够好)。创建索引非常快,尤其是部分索引相对较小。此解决方案也不需要向表中添加任何内容。
假设没有对表的并发访问,可以使用如下函数完成自动索引重新创建:
1 2 3 4 5 6 7 8 9 10 11 12 13 | CREATE OR REPLACE FUNCTION f_index_recreate() RETURNS void AS $func$ BEGIN DROP INDEX IF EXISTS queries_recent_idx; EXECUTE format(' CREATE INDEX queries_recent_idx ON queries_query (user_sid, created) WHERE created > %L::timestamp' , LOCALTIMESTAMP - INTERVAL '30 days'); -- timestamp constant -- , now() - interval '30 days'); -- alternative for timestamptz END $func$ LANGUAGE plpgsql; |
呼叫:
1 | SELECT f_index_recreate(); |
- 仅选择今天(从午夜开始)时间戳
用Postgres 9.2 - 9.4测试。
SQL小提琴。
如果必须处理并发访问,请使用
... a regular
CREATE INDEX command can be performed within a transaction
block, butCREATE INDEX CONCURRENTLY cannot.
因此,有两个单独的交易:
1 2 | CREATE INDEX CONCURRENTLY queries_recent_idx2 ON queries_query (user_sid, created) WHERE created > '2013-01-07 00:00'::TIMESTAMP; -- your new condition |
然后:
1 | DROP INDEX CONCURRENTLY IF EXISTS queries_recent_idx; |
(可选)重命名为旧名称:
1 | ALTER INDEX queries_recent_idx2 RENAME TO queries_recent_idx; |
2.具有"存档"标签条件的部分索引
在表中添加
1 | ALTER queries_query ADD COLUMN archived BOOLEAN NOT NULL DEFAULT FALSE; |
1 2 | CREATE INDEX some_index_name ON queries_query (user_sid, created) WHERE NOT archived; |
为查询添加匹配条件(即使看起来多余),以允许它使用索引。检查
您不必删除并重新创建索引,但表中的
我会选择第一个选项(索引娱乐)。事实上,我在几个数据库中使用此解决方案。第二个会导致更高成本的更新。
随着时间的推移,两种解决方案都保持其有用性,随着索引中包含更多过时的行,性能会逐渐恶化。