错误:索引表达式中的函数必须在 Postgres 中标记为 IMMUTABLE

发布于 2024-11-06 20:03:47 字数 788 浏览 0 评论 0原文

我想创建多列表达式索引,但是当我创建索引时,输出以下消息:

--detail message 
wapgrowth=> create index CONCURRENTLY idx_test on  tmp_table using btree (skyid, to_char(create_time, 'YYYY-MM-DD'), actiontype );
ERROR:  functions in index expression must be marked IMMUTABLE


--table ddl
wapgrowth=> \d tmp_table
               Table "wapgrowth.tmp_table"
   Column    |            Type             |   Modifiers   
-------------+-----------------------------+---------------
 id          | integer                     | not null
 actiontype  | character varying(20)       | 
 apptype     | character varying(20)       | 
 score       | integer                     | 
 create_time | timestamp without time zone | default now()
 skyid       | integer                     | 
Indexes:

I want to create a Multicolumn expression index, but when I create the index, the following message is output:

--detail message 
wapgrowth=> create index CONCURRENTLY idx_test on  tmp_table using btree (skyid, to_char(create_time, 'YYYY-MM-DD'), actiontype );
ERROR:  functions in index expression must be marked IMMUTABLE


--table ddl
wapgrowth=> \d tmp_table
               Table "wapgrowth.tmp_table"
   Column    |            Type             |   Modifiers   
-------------+-----------------------------+---------------
 id          | integer                     | not null
 actiontype  | character varying(20)       | 
 apptype     | character varying(20)       | 
 score       | integer                     | 
 create_time | timestamp without time zone | default now()
 skyid       | integer                     | 
Indexes:

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

情何以堪。 2024-11-13 20:03:47

根据黑客邮件列表中的此线程:

http://www .mail-archive.com/[email protected]/msg86725.html

这是预期的行为,因为 to_char 取决于 LC_MESSAGES

设置这种情况显然没有意义,因为您使用的格式永远不会依赖于区域设置,因此如果您确实需要在索引中使用文本表示形式,您可以创建自己的 to_char() 函数并将其标记为不可变:

CREATE OR REPLACE FUNCTION my_to_char(some_time timestamp) 
  RETURNS text
AS
$BODY$
    select to_char($1, 'yyyy-mm-dd');
$BODY$
LANGUAGE sql
IMMUTABLE;

如果您必须将其用作索引中的文本(并且不能像 Sam 建议的那样使用日期转换),您将需要创建自己的格式化函数,您可以将其标记为不可变。然后可以在索引中使用它。

但要使 Postgres 使用索引,您还需要在 SQL 语句中调用 my_to_char()。当您使用内置的 to_char() 时,它不会识别它,

但我确实认为 Sam 的建议在索引中使用直接日期可能更好

According to this thread in the hackers mailing list:

http://www.mail-archive.com/[email protected]/msg86725.html

this is intended behaviour as to_char depends on the LC_MESSAGES setting

In your case this apparently doesn't make sense as the format you are using will never depend on the locale, so if you do need to use the text representation in the index, you can create your own to_char() function and mark it as immutable:

CREATE OR REPLACE FUNCTION my_to_char(some_time timestamp) 
  RETURNS text
AS
$BODY$
    select to_char($1, 'yyyy-mm-dd');
$BODY$
LANGUAGE sql
IMMUTABLE;

If you have to use it as a text in the index (and cannot use the cast to a date as Sam suggested) you will need to create your own formatting function that you can mark as immutable. That can then be used in the index.

But to make Postgres use the index you will need to call my_to_char() in your SQL statements as well. It will not recognize it when you use the built-in to_char()

But I do think Sam's suggestion using a straight date in the index is probably better

找个人就嫁了吧 2024-11-13 20:03:47

这更详细地解释了:

https://www.postgresql.org/message-id/CAKFQuwbcMfesmNkm19mXFLXP14sP5BiPsR1GSkY1suKiM1rukg%40mail.gmail.com

基本上时区取决于服务器,因此如果有人更改它,结果可能会改变。但如果你锁定时区:

date(timezone('UTC', create_time))

它将起作用。

This explains more in detail:

https://www.postgresql.org/message-id/CAKFQuwbcMfesmNkm19mXFLXP14sP5BiPsR1GSkY1suKiM1rukg%40mail.gmail.com

basically the timezone depends on the server, and thus the result might change if somebody changes it. But if you lock the timezone:

date(timezone('UTC', create_time))

it will work.

丢了幸福的猪 2024-11-13 20:03:47

timestamp-without-timezone 的 to_char 不是一个不可变的函数,因为转换取决于您本地的时区设置。这意味着索引无法移植到不同时区的另一台计算机,Postgres 也不允许这样做。我认为如果您将 create_time 声明为带时区的时间,问题就会消失。

to_char of a timestamp-without-timezone is not an immutable function, because the conversion depends on your local time-zone setting. That means the index wouldn't be portable to another computer in a different time zone, and Postgres won't allow it. I think the problem will go away if you declare create_time as a time with timezone.

撩起发的微风 2024-11-13 20:03:47

不要使用 to_char 将时间戳格式化为 YYYY-MM-DD,而是尝试将时间戳转换为日期类型,这将具有相同的效果:

create index CONCURRENTLY idx_test on  tmp_table using btree (skyid, cast(create_time as date), actiontype );

Instead of using to_char to format your timestamp as YYYY-MM-DD, try casting your timestamp to a date type, which will have the same effect:

create index CONCURRENTLY idx_test on  tmp_table using btree (skyid, cast(create_time as date), actiontype );
晨与橙与城 2024-11-13 20:03:47

归根结底,您似乎正在尝试对 create_time 的“YYYY-MM-DD”表示形式建立索引。为什么不只使用 INDEX create_time 呢?问题是 to_char() 是可变的,因为区域设置环境变量可能会更改,这会更改 to_char() 的输出。

http://www.postgresql.org/docs/current/static/charset。 html

如果您可以控制模式,您可以添加一个新列(例如 create_date TEXT)并对其进行索引,然后设置一个处理插入的触发器。事实上,如果您创建了一种将 TIMESTAMP without TIME ZONE 转换为 TEXT 的方法,您可以以恒定的方式对其进行索引。 a_horse_with_no_name 的建议是一个很好的建议,因为我认为你不关心语言环境。

您遇到的问题是所有 DATE 和 TIME 处理代码都遵循区域设置,这不是 IMMUTABLE,因此您无法轻松地使用依赖于这些数据类型的 INDEX 函数。

At the end of the day it looks like you're trying to index a "YYYY-MM-DD" representation of create_time. Why not just INDEX create_time? The problem is to_char() is MUTABLE because the locale environment variable could change, which changes the output of to_char().

http://www.postgresql.org/docs/current/static/charset.html

If you have control over the schema, you could add a new column (e.g. create_date TEXT) and INDEX that, then setup a trigger that handles the inserts. In fact, if you created a way of converting your TIMESTAMP WITHOUT TIME ZONE to TEXT, you could INDEX that in a constant way. a_horse_with_no_name's suggestion was a good one since I don't think you care about locale.

The problem you're running in to is all DATE and TIME handling code obeys locale, which isn't IMMUTABLE, therefore you can't easily INDEX functions that rely on those data types.

月隐月明月朦胧 2024-11-13 20:03:47

对于 timestamptz 字段,它看起来像这样:

CREATE INDEX idx_name ON your_table(EXTRACT(YEAR FROM your_column_timestamptz AT TIME ZONE 'UTC'));

for the timestamptz field, it looks like this:

CREATE INDEX idx_name ON your_table(EXTRACT(YEAR FROM your_column_timestamptz AT TIME ZONE 'UTC'));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文