Может ли столбцы столбцов индекса PostgreSQL?

Я не могу найти определенный ответ на этот вопрос в документации. Если столбец является типом массива, будут ли все введенные значения индивидуально проиндексированы?

Я создал простую таблицу с одним столбцом int[] и поместил на нее уникальный индекс. Я заметил, что я не могу добавить один и тот же массив int, что заставляет меня думать, что индекс является составной частью элементов массива, а не индексом каждого элемента.

INSERT INTO "Test"."Test" VALUES ('{10, 15, 20}');
INSERT INTO "Test"."Test" VALUES ('{10, 20, 30}');

SELECT * FROM "Test"."Test" WHERE 20 = ANY ("Column1");

Помогает ли этот запрос этому запросу?

Ответ 1

Да, вы можете индексировать массив, но вы должны использовать операторы массива и тип индекса GIN.

Пример:

    CREATE TABLE "Test"("Column1" int[]);
    INSERT INTO "Test" VALUES ('{10, 15, 20}');
    INSERT INTO "Test" VALUES ('{10, 20, 30}');

    CREATE INDEX idx_test on "Test" USING GIN ("Column1");

    -- To enforce index usage because we have only 2 records for this test... 
    SET enable_seqscan TO off;

    EXPLAIN ANALYZE
    SELECT * FROM "Test" WHERE "Column1" @> ARRAY[20];

Результат:

Bitmap Heap Scan on "Test"  (cost=4.26..8.27 rows=1 width=32) (actual time=0.014..0.015 rows=2 loops=1)
  Recheck Cond: ("Column1" @> '{20}'::integer[])
  ->  Bitmap Index Scan on idx_test  (cost=0.00..4.26 rows=1 width=0) (actual time=0.009..0.009 rows=2 loops=1)
        Index Cond: ("Column1" @> '{20}'::integer[])
Total runtime: 0.062 ms
Примечание

похоже, что во многих случаях требуется опция gin__int_ops

create index <index_name> on <table_name> using GIN (<column> gin__int_ops)

Я еще не видел случая, чтобы он работал с операторами && и @> без параметров gin__int_ops

Ответ 2

@Tregoreg поднял вопрос в комментарии к предложенной награде:

Я не нашел, что текущие ответы работают. Использование индекса GIN для столбца с массивом не увеличивает производительность оператора ANY(). Неужели нет решения?

@Frank принял ответ говорит вам использовать операторы массива, который до сих пор правильно для Postgres 11. Учебное пособие:

... стандартный дистрибутив PostgreSQL включает класс операторов GIN для массивов, который поддерживает индексированные запросы с использованием этих операторов:

<@
@>
=
&&

Полный список встроенных классов операторов для индексов GIN в стандартном выпуске находится здесь.

В Postgres индексы связаны с операторами (которые реализованы для определенных типов), а не только с типами данных или функциями или чем-то еще. Это наследие от оригинального дизайна Беркли Postgres и очень трудно изменить сейчас. И это вообще работает просто отлично. Вот ветка о pgsql-ошибках, которую комментирует Том Лейн.

Некоторые функции PostGis (например, ST_DWithin()), кажется, нарушают этот принцип, но это не так.Эти функции переписаны для использования соответствующими операторами.

Индексированное выражение должно быть слева от оператора. Для большинства операторов (включая все вышеперечисленное) планировщик запросов может достичь этого путем переключения операндов, если поместить индексированное выражение вправо, учитывая, что определен COMMUTATOR. ANY конструкция может использоваться в сочетании с различными операторами и не является самим оператором. При использовании в качестве constant = ANY (array_expression) только индексы, поддерживающие оператор = для элементов массива, и нам понадобится коммутатор для = ANY(). Индексы GIN отсутствуют.

В настоящее время Postgres недостаточно умен, чтобы вывести из него индексируемое GIN-выражение. Для начала, constant = ANY (array_expression) не полностью эквивалентна array_expression @> ARRAY[constant]. Операторы массива возвращают ошибку, если задействованы какие-либо элементы NULL, а конструкция ANY может работать с NULL с любой стороны. И есть разные результаты для несоответствия типов данных.

Связанные ответы:

Asides

При работе с integer массивами (int4, а не int2 или int8) без значений NULL (как подразумевается в вашем примере) рассмотрите дополнительный модуль intarray, который обеспечивает специализированные, более быстрые операторы и поддержку индексов. Увидеть:

Что касается ограничения UNIQUE в вашем вопросе, которое осталось без ответа: оно реализовано с помощью индекса btree для всего значения массива (как вы и подозревали) и вообще не помогает с поиском элементов. Подробности:

Ответ 3

Теперь можно индексировать отдельные элементы массива. Например:

CREATE TABLE test (foo int[]);
INSERT INTO test VALUES ('{1,2,3}');
INSERT INTO test VALUES ('{4,5,6}');
CREATE INDEX test_index on test ((foo[1]));
SET enable_seqscan TO off;

EXPLAIN ANALYZE SELECT * from test WHERE foo[1]=1;
                                                QUERY PLAN                                                    
------------------------------------------------------------------------------------------------------------------
 Index Scan using test_index on test  (cost=0.00..8.27 rows=1 width=32) (actual   time=0.070..0.071 rows=1 loops=1)
   Index Cond: (foo[1] = 1)
 Total runtime: 0.112 ms
(3 rows)

Это работает, по крайней мере, в Postgres 9.2.1. Обратите внимание, что вам нужно создать отдельный индекс для каждого индекса массива, в моем примере я только проиндексировал первый элемент.