Может ли PostgreSQL индексировать столбцы массива?
Я не могу найти однозначный ответ на этот вопрос в документации. Если столбец является типом массива, будут ли все введенные значения индексироваться индивидуально?
Я создал простую таблицу с одним int[]
столбец и поместите на него уникальный индекс. Я заметил, что не могу добавить один и тот же массив ints, что заставляет меня полагать, что индекс является составным элементом массива, а не индексом каждого элемента.
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 ответов
Да, вы можете индексировать массив, но вы должны использовать операторы массив и тип Джин-индекса.
пример:
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
Отмечать
оказывается, что во многих случаях Джин_ _ int _ ops требуется
create index <index_name> on <table_name> using GIN (<column> gin__int_ops)
Я еще не видел случая, когда он работал бы с оператором & & и @> без параметров Gin__int_ops
@Tregoreg поднял вопрос в комментарии к его предложил баунти:
я не нашел, что текущие ответы работают. Использование индекса GIN на Array-typed столбец не увеличивает производительность любого() оператор. Неужели нет никакого решения?
@Фрэнк принял ответ говорит, что вы должны использовать операторы массив, которая составляет еще правильно для Postgres 10. инструкции:
стандартное распределение PostgreSQL включает классы операторов GIN для одномерных массивов, которые поддерживают индексированные запросы, использующие эти операторы:
<@ @> = &&
В Postgres индексы привязаны к операторам, а не данные типы, функции или что-нибудь еще. Это наследие от оригинального дизайна Беркли Postgres и очень трудно изменить. И, как правило, это работает просто отлично. вот поток на pgsql-ошибки с Томом Лейном, комментирующим это.
индексированное выражение должно быть левый оператора. Для большинства операторов (, включая все вышеперечисленное) планировщик запросов может достичь этого, перевернув операнды, если вы поместите индексированное выражение справа-учитывая, что a COMMUTATOR
была определена. The ANY
построить может использоваться в сочетании с различными операторами и не является самим оператором. При использовании как constant = ANY (array_expression)
только индексы обслуживания =
оператор on элементы массива будет квалифицироваться, и нам понадобится коммутатор для = ANY()
. Gin-индексов нет.
Postgres в настоящее время недостаточно умен, чтобы получить индексируемый GIN выражение от него. Для начала, constant = ANY (array_expression)
is не совсем эквивалентно до array_expression @> ARRAY[constant]
. Операторы массива возвращают ошибку, если любой NULL элементов, а ANY
construct может иметь дело с NULL с любой стороны. И есть разные результаты для несоответствий типов данных.
соответствующие ответы:
для поиск элемента в массиве JSON
Asides
, работая с integer
массивы (int4
, а не int2
или int8
) без NULL
значения (как следует из вашего примера) рассмотрим дополнительные модуль intarray
, который обеспечивает специализированные, более быстрые операторы и поддержку индекса. См.:
- как создать индекс для элементов массива в PostgreSQL?
- сравнить массивы для равенства, игнорируя порядок элементов
что касается UNIQUE
ограничение в вашем вопросе, который остался без ответа: это реализовано с индексом btree на весь массив значение (как вы подозревали) и не помогает в поиске элементов на всех. Подробности:
теперь можно индексировать отдельные элементы массива. Например:
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. Обратите внимание, что вам нужно создать отдельный индекс для каждого индекса массива, в моем примере я индексировал только первый элемент.