GIN index on smallint[] column not used or error “operator is not unique”

前端 未结 1 389
不知归路
不知归路 2020-12-20 00:27
create table test(
    id serial primary key,
    tagged smallint[]
);

There is gin index on tagged column, with _int2_ops

相关标签:
1条回答
  • 2020-12-20 01:21

    Solution

    Most probably, the solution is to schema-qualify the operator:

    SELECT *
    FROM   test
    WHERE  tagged OPERATOR(pg_catalog.@>) '{11}'::int2[]
    ORDER  BY id
    LIMIT  100;

    Why?

    It's a problem of operator resolution (in combination with type resolution and cast context).

    In standard Postgres, there is only a single candidate operator anyarray @> anyarray, that's the one you want.

    Your setup would work just fine if you had not installed the additional module intarray (my assumption), which provides another operator for integer[] @> integer[].

    Hence, another solution would be to use integer[] instead and have a GIN index with the gin__int_ops operator class. Or try the (default for intarray) gist__int_ops index. Either might be faster, but both don't allow NULL values.
    Or you could rename the intarray operator @> to disambiguate. (I would not do that. Upgrade and portability issues ensue.)

    For expressions involving at least one operand of type integer[], Postgres knows which operator to pick: the intarray operator. But then the index is not applicable, because the intarray operator only operates on integer (int4) not int2. And indexes are strictly bound to operators:

    • Can PostgreSQL index array columns?
    • PostgreSQL behavior in presence of two different type of indexes on the same column

    But for int2[] @> int2[], Postgres is unable to decide the best operator. Both seem equally applicable. Since the default operator is provided in the pg_catalog schema and the intarray operator is provided in the public schema (by default - or wherever you installed the extension), you can help solve the conundrum by schema-qualifying the operator with the OPERATOR() construct. Related:

    • Compare arrays for equality, ignoring order of elements

    The error message you get is a bit misleading. But if you look closely, there is a HINT line added which hints (tada!) in the right direction:

    ERROR:  operator is not unique: smallint[] @> smallint[]
    LINE 1: SELECT NULL::int2[] @> NULL::int2[]
                                ^
    HINT:  Could not choose a best candidate operator. You might need to add explicit type casts.
    

    You can investigate existing operator candidates for @> with:

    SELECT o.oid, *, oprleft::regtype, oprright::regtype, n.nspname
    FROM   pg_operator o
    JOIN   pg_namespace n ON n.oid = o.oprnamespace
    WHERE  oprname = '@>';
    

    Another alternative solution would be to temporarily(!) set a different search_path, so only the desired operator is found. In the same transaction:

    SET LOCAL search_path = pg_catalog;
    SELECT ...
    

    But then you have to schema-qualify all tables in the query.

    About cast context:

    • Generate series of dates - using date type as input

    You could change the castcontext of int2 -> int4. But I strongly advise against it. Too many possible side effects:

    • Is there any way to cast postgresql 9.3 data type so that it can affect only one side
    0 讨论(0)
提交回复
热议问题