Может ли PostgreSQL индексировать столбцы массивов? - PullRequest
121 голосов
/ 30 октября 2010

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

Я создал простую таблицу с одним столбцом 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");

Помогает ли индекс этомузапрос

Ответы [ 3 ]

146 голосов
/ 30 октября 2010

Да, вы можете индексировать массив, но вы должны использовать операторы массива и тип индекса 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

76 голосов
/ 25 марта 2015

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

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

@ Фрэнк принял ответ говорит вам использовать операторы массива , что все еще корректно для 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 для значения весь массив (как вы и предполагали) и не помогает при поиске элементы на всех. Подробности:

34 голосов
/ 13 ноября 2012

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

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. Обратите внимание, что вам нужно создать отдельный индекс для каждого индекса массива, в моем примере я проиндексировал только первый элемент.

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