Індекс максимальної помилки розміру рядка


12

Чи є верхня межа для arrayстовпця?

Я отримую цю помилку під час вставки в поле масиву -

PG::Error: ERROR:  index row size 3480 exceeds maximum 2712 for index "ix_data"

Ось моє визначення таблиці -

create table test_array(id varchar(50), data text[]);

ALTER TABLE test_array ADD PRIMARY KEY (id);

CREATE INDEX ix_data ON test_array USING GIN (data);

Мені потрібен індекс поля масиву, оскільки я роблю деякі пошуки на ньому.


Можливо, він dataмістить список тегів, як це демонстрував у цій пов’язаній публікації блогу Скотт Снайдер ? Якщо це так, я можу мати краще рішення для вас.
Ервін Брандстеттер

user310525, я хотів би надати другу пропозицію Ервіна про те, що це буде краще на dba.se, якщо ви готові створити там обліковий запис і позначити для міграції модератор?
Джек каже, спробуйте topanswers.xyz

Відповіді:


14

Проблема

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

Повністю функціональна демо-версія на sqlfiddle.


2

Помилка в індексі ix_data, а не в text[]полі. Максимальний розмір рядка у конкретному типі індексу обмежений 2712байтами. Якщо ви кинете свій індекс і спробуйте вставити ще раз, він повинен працювати для вас. Якщо вам потрібно проіндексувати велике поле, можливо, ви захочете ознайомитися з повноцінними характеристиками індексації тексту постгресів.


2

Я отримував це в колонці з географії PostGIS. Це було тому, що я випадково створив індекс неправильно. Ви повинні включати параметр USING GIST при створенні таких індексів.


Дякую - це було все! Нічого собі, поки що вийшло. Можливо, врятували мені години. Тим більше, що я вважав, що GiST використовується за замовчуванням, але я помилився, і він намагається використовувати b-tree.
Йонас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.