Я не могу найти однозначного ответа на этот вопрос в документации. Если столбец имеет тип массива, будут ли все введенные значения индексироваться индивидуально?
Я создал простую таблицу с одним 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");
Помогает ли индекс этому запросу?
arrays
postgresql
indexing
IamIC
источник
источник
jsonb
и индексы? postgresql.org/docs/9.5/static/functions-json.html и postgresql.org/docs/9.5/static/datatype-json.html#JSON-INDEXINGОтветы:
Да, вы можете индексировать массив, но вы должны использовать операторы массива и тип индекса 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];
Результат:
Заметкапохоже, что во многих случаях требуется опция gin__int_ops
create index <index_name> on <table_name> using GIN (<column> gin__int_ops)
Я еще не видел случая, чтобы он работал с операторами && и @> без параметров gin__int_ops
источник
gin__int_ops
не используются дляinteger[]
столбцов. Мне потребовались годы разочарования и поиск других решений, пока я не обнаружил этот операционный класс. Это пограничный чудотворец.@Tregoreg поднял вопрос в комментарии к предложенной им награде:
В принятом ответе @Frank предлагается использовать операторы массива , что по- прежнему верно для Postgres 11. Руководство:
Полный список классов встроенных операторов для индексов GIN в стандартной поставке находится здесь.
В Postgres индексы привязаны к операторам (которые реализованы для определенных типов), а не только к типам данных, функциям или чему-либо еще. Это наследие оригинального дизайна Postgres в Беркли, и сейчас его очень сложно изменить. И в целом работает нормально. Вот ветка pgsql-bugs, где Том Лейн комментирует это.
Некоторые функции PostGis (например,
ST_DWithin()
) нарушают этот принцип, но это не так. Эти функции внутренне переписаны для использования соответствующих операторов .Проиндексированное выражение должно находиться слева от оператора. Для большинства операторов ( включая все вышеперечисленные ) планировщик запросов может добиться этого, переворачивая операнды, если вы поместите индексированное выражение вправо - при условии, что
COMMUTATOR
был определен a .ANY
Конструкция может быть использована в комбинации с различными операторами и не является сам оператор. При использованииconstant = ANY (array_expression)
только индексы, поддерживающие=
оператор для элементов массива, будут квалифицированы, и нам понадобится коммутатор для= ANY()
. Индексы GIN отсутствуют.Postgres в настоящее время недостаточно умен, чтобы получить из него выражение, индексируемое GIN. Во - первых,
constant = ANY (array_expression)
это не полностью эквивалентны сarray_expression @> ARRAY[constant]
. Операторы массива возвращают ошибку, если задействованы какие-либо элементы NULL , в то время какANY
конструкция может обрабатывать NULL с любой стороны. И есть разные результаты для несоответствия типов данных.Связанные ответы:
Проверить, существует ли значение в массиве Postgres
Индекс для поиска элемента в массиве JSON
SQLAlchemy: как фильтровать типы столбцов PgArray?
Можно ли как-то объединить ЕСТЬ ОТЛИЧИЕ ОТ С ЛЮБОЙ или ВСЕ?
В сторону
При работе с
integer
массивами (int4
, неint2
илиint8
) безNULL
значений (как предполагает ваш пример) рассмотрите дополнительный модульintarray
, который предоставляет специализированные, более быстрые операторы и поддержку индексов. Увидеть:Что касается
UNIQUE
ограничения в вашем вопросе, который остался без ответа: это реализовано с помощью индекса btree для всего значения массива (как вы и подозревали) и вообще не помогает с поиском элементов . Детали:источник
gin__int_ops
не используются дляinteger[]
столбцов. Мне потребовались годы разочарования и поиск других решений, пока я не обнаружил этот операционный класс. Это пограничный чудотворец.ANY (array_expression) = constant
выражений индексы GIN работают нормально?Теперь можно индексировать отдельные элементы массива. Например:
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. Обратите внимание, что вам нужно создать отдельный индекс для каждого индекса массива, в моем примере я проиндексировал только первый элемент.
источник