web-dev-qa-db-ja.com

INDEXでCONCATを使用するとエラーが発生します。インデックス式の関数はIMMUTABLEとマークする必要があります

次のエラーが発生しています。

_ERROR:  functions in index expression must be marked IMMUTABLE
_

このようなインデックスを作成しようとすると:

_CREATE INDEX full_phone_number ON orders_clientphone (concat(area_code, phone));
_

一方、連結に代替構文を使用する場合:

_CREATE INDEX full_phone_number ON orders_clientphone ((area_code || phone));
_

Postgresはそれでかなり大丈夫です。
両方の列はcharacter varying(256)として定義されています。

6
andilabs

Postgresの決定要因は、関数concat()が定義されていることですstableおよびではありません不変システムカタログ_pg_proc_:

_SELECT proname, provolatile, proargtypes, proargtypes[0]::regtype AS argtype, prosrc
FROM pg_proc
WHERE proname = 'concat';

proname | provolatile | proargtypes| argtype | prosrc
--------+-------------+------------+---------+-----------
concat  | s           | 2276       | "any"   | text_concat
_

_pg_proc.provolatile_: のマニュアル

provolatileは、関数の結果が入力引数のみに依存するのか、それとも外部要因の影響を受けるのかを示します。 「不変」関数の場合はiであり、常に同じ入力に対して同じ結果を提供します。これは「安定した」関数の場合はsであり、その結果(固定入力の場合)はスキャン内で変化しません。

また、関数の引数タイプ(_"any"_)を追加して、@ dezsoおよび@jjanesの回答に接続しました。これにより、この関数のみを安定させるという決定の背後にある根拠が提供されます。そして、内部関数の名前(_text_concat_)。

以下は、インデックス式の不変性が正弦非条件である理由を説明するための関連質問です。

演算子_||_の使用について:

_    SELECT o.oprname, o.oprleft::regtype, o.oprright::regtype, o.oprcode, p.provolatile
    FROM   pg_operator o
    JOIN   pg_proc     p ON p.oid = o.oprcode
    WHERE  oprname = '||';


 oprname |   oprleft   |  oprright   |     oprcode     | provolatile
---------+-------------+-------------+-----------------+-------------
 ||      | anyarray    | anyelement  | array_append    | i
 ||      | anyelement  | anyarray    | array_prepend   | i
 ||      | anyarray    | anyarray    | array_cat       | i
 ||      | text        | text        | textcat         | i
 ||      | bit varying | bit varying | bitcat          | i
 ||      | bytea       | bytea       | byteacat        | i
 ||      | text        | anynonarray | textanycat      | s
 ||      | anynonarray | text        | anytextcat      | s
 ||      | tsvector    | tsvector    | tsvector_concat | i
 ||      | tsquery     | tsquery     | tsquery_or      | i
 ||      | jsonb       | jsonb       | jsonb_concat    | i
_

内部で使用する関数は、オペランドの実際のデータ型によって異なります。演算子の定義には、Postgresのオペランドのデータ型が含まれます。すべての関数は異なり、上記の_text_concat_とも異なります。演算子の1つがanynonarrayの場合、_||_も安定します。カーテンの後ろでは物事はそれほど簡単ではありません。

character varying(256)(他のvarcharバリアントと同様)はbinary-coercibleto text so function type resolution デフォルトはtextです。

6

次のように、concat、 ドキュメントで定義 と考えています。

FUNCTION                                  RETURN TYPE  DESCRIPTION
-----------------------------------------------------------------------------------
concat(str "any" [, str "any" [, ...] ])  text         Concatenate the text repre-
                                                       sentations of all the arguments. 
                                                       NULL arguments are ignored.

テキスト表現はデータベース設定に依存する可能性があるため、不変ではありません 日付またはタイムスタンプのように

3
dezso

Dezsoの答えを記入するために、データベースの状態に応じて異なる出力を生成する同じ入力の例を次に示します。

select concat(1.0000000000003::float8,56);

1.000000000000356

set extra_float_digits TO 3;

select concat(1.0000000000003::float8,56);

1.0000000000002999856
3
jjanes