2010-10-30 2 views
99

Я не могу найти определенный ответ на этот вопрос в документации. Если столбец является типом массива, будут ли все введенные значения индивидуально проиндексированы?Может ли столбцы столбцов индекса 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"); 

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

+0

Можно ли использовать тип данных 'jsonb' и использовать индексы? https://www.postgresql.org/docs/9.5/static/functions-json.html и https://www.postgresql.org/docs/9.5/static/datatype-json.html#JSON-INDEXING – user3791372

ответ

119

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

Пример:

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 
+16

Как ОП полагает, что это фактически не индексирует отдельные значения массива, а вместо этого индексирует весь массив. Таким образом, хотя это поможет в вопросе (см. План объяснения), это означает, что вы не можете создавать уникальные ограничения (легко) для отдельных значений массива. Тем не менее, если вы используете целые массивы, вы можете использовать модуль contrib «intarray» для индексации значений отдельных массивов, что во многих случаях может быть намного быстрее. (IIRC там делается некоторая работа над этим для текстовых значений, но вкладчики, вероятно, были бы рады помочь ему завершить). – xzilla

+6

Пожалуйста, не используйте заглавные буквы в идентификаторах PostgreSQL в примерах кода, это просто путает людей, которые не знакомы с правилами раскладки кавычек/случаев, особенно людьми, новыми для PostgreSQL. – intgr

+1

Чтобы повторить мой комментарий здесь: по моему опыту, эти индексы почти не ускоряются * если * 'gin__int_ops' не используется для столбцов integer []'. Мне потребовались годы разочарования и поиска других решений, пока я не открыл этот класс op. Это пограничный чудотворец. – IamIC

32

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

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

+19

Пусть это не будет потеряно - этот подход безнадежен для массива переменной длины, где вы хотите использовать оператор ANY(). –

+11

Это действительно не очень полезно. Если у вас есть фиксированное количество элементов массива, вы предпочитаете использовать отдельные столбцы для каждого элемента (и простые индексы btree) вместо того, чтобы строить более дорогой индекс выражения для каждого элемента массива. Хранение отдельных столбцов намного дешевле без избыточного массива. –

58

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

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

@Frank's accepted answer говорит вам использовать операторов массива, который является еще правильна в 2015.
Per documentation:

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

<@ 
@> 
= 
&& 

The complete list of built-in operator classes for GIN indexes in the standard distribution is here.

В Postgres индексы связаны с операторами, а не типы данных или функции или что-нибудь еще. Это heritage from the original Berkeley design of Postgres и очень сложно изменить сейчас. И это нормально работает. Here is a thread on pgsql-bugs with Tom Lane commenting on this.

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

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

Похожие ответы:


Что касается UNIQUE ограничения в вашем вопросе, который остался без ответа: Это осуществляется с индексом ВТКЕЯ на всю стоимости массива (как вы подозреваемые) и не помогает с поиском для элементов вообще , Реквизиты:

+0

Aaaaaaah, чувствуя себя довольно смущенным прямо сейчас, но мне просто не приходило в голову, что postgres не будут использовать индекс, даже если теоретически это возможно.Возможно, это связано также с тем, что мое отсутствие понимания постгрейсов, таких как эти индексы, связано с операторами. Спасибо, что нашли время, чтобы ответить на мой неправильный вопрос и поделиться своими знаниями! – Tregoreg

+6

@Tregoreg: Не стесняйтесь, это действительно не слишком очевидно. Я помню, как меня смутило это, когда я впервые столкнулся с этим. Добавленный вопрос и разъяснение должны быть весьма полезными для широкой общественности. –

+0

По моему опыту, эти индексы почти не ускоряются * если * 'gin__int_ops' не используется для столбцов' integer [] '. Мне потребовались годы разочарования и поиска других решений, пока я не открыл этот класс op. Это пограничный чудотворец. – IamIC

Смежные вопросы