ОШИБКА: функции в выражении индекса должны быть помечены как IMMUTABLE в Postgres - PullRequest
17 голосов
/ 12 мая 2011

Я хочу создать индекс выражения Multicolumn, но когда я создаю индекс, выводится следующее сообщение:

--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:

Ответы [ 4 ]

19 голосов
/ 12 мая 2011

Согласно этой теме в списке рассылки хакеров:

http://www.mail-archive.com/pgsql-hackers@postgresql.org/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;

Если вам нужно использовать его как текст в индексе (и вы не можете использовать приведение кдата, как предложил Сэм) вам нужно будет создать собственную функцию форматирования, которую вы можете пометить как неизменную.Затем его можно использовать в индексе.

Но для того, чтобы Postgres использовал индекс, вам нужно будет также вызвать my_to_char() в ваших операторах SQL.Он не распознает его, когда вы используете встроенный to_char()

Но я думаю, что предложение Сэма с использованием прямой даты в индексе, вероятно, лучше

2 голосов
/ 12 мая 2011

Вместо использования to_char для форматирования вашей метки времени в формате ГГГГ-ММ-ДД, попробуйте привести вашу метку времени к типу даты, который будет иметь тот же эффект:

create index CONCURRENTLY idx_test on  tmp_table using btree (skyid, cast(create_time as date), actiontype );
2 голосов
/ 12 мая 2011

to_char метки времени без часового пояса не является неизменной функцией, поскольку преобразование зависит от настройки местного часового пояса.Это означает, что индекс не будет переносимым на другой компьютер в другом часовом поясе, и Postgres не допустит этого.Я думаю, что проблема исчезнет, ​​если вы объявите create_time как время с часовым поясом.

1 голос
/ 12 мая 2011

В конце дня похоже, что вы пытаетесь проиндексировать представление "YYYY-MM-DD" для create_time.Почему не просто INDEX create_time?Проблема в том, что to_char () является MUTABLE, потому что может измениться переменная окружения локали, которая изменяет вывод to_char ().

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

Если у вас есть контроль над схемой, вы можетедобавьте новый столбец (например, create_date TEXT) и INDEX, а затем установите триггер, который обрабатывает вставки.Фактически, если вы создали способ преобразования вашего TIMESTAMP БЕЗ ВРЕМЕННОЙ ЗОНЫ в TEXT, вы могли бы ПОКАЗАТЬ это постоянным способом.Предложение a_horse_with_no_name было хорошим, так как я не думаю, что вы заботитесь о локали.

Проблема, с которой вы сталкиваетесь, заключается в том, что весь код обработки DATE и TIME подчиняется локали, что не является НЕММУТНЫМ, поэтому вы можетене легко INDEX функции, которые полагаются на эти типы данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...