Эта проблема
Вот очень похожий случай, обсуждаемый на pgsql.general . Речь идет об ограничении в индексе b-дерева, но это все то же самое, потому что индекс GIN внутренне использует индекс b-дерева для ключей и, следовательно, сталкивается с тем же ограничением для размера ключа (вместо размера элемента в простом b-дереве). показатель).
Я цитирую руководство по реализации индекса GIN :
Внутри индекс GIN содержит индекс B-дерева, построенный по ключам, где каждый ключ является элементом одного или нескольких проиндексированных элементов.
В любом случае, по крайней мере один элемент массива в вашем столбце data
слишком велик для индексации. Если это просто единичное значение или какая-то случайность, вы можете усечь значение и покончить с этим.
Для следующей демонстрации я буду предполагать иначе: множество длинных текстовых значений в массиве.
Простое решение
Вы можете заменить элементы в вашем массиве data
соответствующими значениями хеша . И отправлять значения поиска через ту же хеш-функцию. Конечно, вы, вероятно, хотите где-то хранить свои оригиналы. С этим мы почти приходим ко второму варианту ...
Усовершенствованное решение
Вы можете создать справочную таблицу для элементов массива со serial
столбцом в качестве суррогатного первичного ключа (фактически это радикальный вид хеш-значения), что тем более интересно, если значения участвующих элементов не являются уникальными:
CREATE TABLE elem (
elem_id serial NOT NULL PRIMARY KEY
, elem text UNIQUE NOT NULL
);
Так как мы хотим , чтобы посмотреть elem
, мы добавим индекс - но в индекс на выражении на этот раз, и только первые 10 символов длинного текста. В большинстве случаев этого должно быть достаточно, чтобы сузить поиск до одного или нескольких обращений. Адаптируйте размер к вашему распределению данных. Или используйте более сложную хэш-функцию.
CREATE INDEX elem_elem_left10_idx ON elem(left(elem,10));
Ваш столбец data
будет иметь тип int[]
. Я переименовал стол в data
и избавился от зловещего, что varchar(50)
вы имели в своем примере:
CREATE TEMP TABLE data(
data_id serial PRIMARY KEY
, data int[]
);
Каждый элемент массива в data
относится к elem.elem_id
. На этом этапе вы можете рассмотреть возможность замены столбца массива таблицей n: m, тем самым нормализуя вашу схему и позволяя Postgres обеспечивать ссылочную целостность. Индексирование и общая обработка становятся проще ...
Однако по соображениям производительности int[]
столбец в сочетании с индексом GIN может быть лучше. Размер хранилища намного меньше. В этом случае нам нужен индекс GIN:
CREATE INDEX data_data_gin_idx ON data USING GIN (data);
Теперь каждый ключ индекса GIN (= элемент массива) integer
вместо длинного text
. Индекс будет меньше на несколько порядков, следовательно, поиск будет намного быстрее.
Недостаток: прежде чем вы действительно сможете выполнить поиск, вы должны посмотреть в elem_id
таблице elem
. Используя мой недавно введенный функциональный индекс elem_elem_left10_idx
, это тоже будет намного быстрее.
Вы можете сделать все это одним простым запросом :
SELECT d.*, e.*
FROM elem e
JOIN data d ON ARRAY[e.elem_id] <@ d.data
WHERE left(e.elem, 10) = left('word1234word', 10) -- match index condition
AND e.elem = 'word1234word'; -- need to recheck, functional index is lossy
Возможно, вас заинтересует расширение intarray
, которое предоставляет дополнительные операторы и классы операторов.
data
содержит список тегов, как показано в этом сообщении в блоге Скотта Снайдера ? Если это так, у меня может быть лучшее решение для вас.