我想在我的表上为 start_time 创建一个索引,这是我的json列中名为 match 的timestamptz(带时区的时间戳)字段。
在this question和this article之后,我了解到由于不同的时区和本地化,你不能在timestamptz字段上创建索引。这两个都表明你可以在时间戳(转换为文本)上创建索引,所以我尝试了以下函数:
CREATE OR REPLACE FUNCTION to_text(timestamptz)
RETURNS text AS $$
SELECT to_char($1 at time zone 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.US')
$$
LANGUAGE sql IMMUTABLE;
字符串
我相信它没有时区和本地化的问题。
CREATE INDEX i_match_start_time ON matches (to_text(((match->>'start_time')::timestamptz)));
型
这将返回以下内容:
错误:索引表达式中的函数必须标记为IMMUTABLE
我也尝试了返回时间戳的函数:
SELECT ($1 at time zone 'UTC')
型
以及返回unix时间的函数(尝试double并转换为decimal):
SELECT EXTRACT(EPOCH FROM $1)
型
每个都返回相同的错误。
我需要在 start_time 上建立索引,因为实际上对这个表的所有选择查询都将按 start_time 排序。
1条答案
按热度按时间utugiqy61#
JSON嵌套
timestamptz
一个
timestamptz
(json列中的timestamp with time zone)
字段JSON中没有 ”
timestamptz
字段” 这回事。JSON只理解:object,array,string,number,boolean,null。我假设这是正确的处理与ISO 8601 timestamptz * 字符串 * 在外地排他性。否则,有更多的问题要解决。
相关博客:
伪
IMMUTABLE
从
text
到timestamptz
的转换本身并不是IMMUTABLE
,它取决于像datestyle
这样的volatile设置。在您的特定情况下,我们可以将强制转换移动到函数中作为解决方案:
字符串
由于只有ISO 8601日期,并且没有依赖于本地化设置的模板模式,这实际上是不可变的。
更好的索引
但是,现在没有必要强制转换为
text
并返回。直接索引返回的timestamptz
值!(您最初假设这是不可能的,这不成立!)型
使用一个“SQL标准”函数(随Postgres 14添加)。参见:
在Postgres 9.6或更高版本中添加
PARALLEL SAFE
。请参阅:更好
实际上,对该表的所有选择查询都将按 start_time 排序。
根据上面的函数添加一个生成的列(Postgres 12添加的),并在其上添加一个普通索引:
型
甚至更简单的日常处理,和更有效.增加8字节支付时使用了很多.见:
或者将时间戳从JSON文档中移到它自己的列中开始开始,这样最好。