Y a-t-il une limite supérieure pour une array
colonne?
Je reçois cette erreur lors de l'insertion dans le champ du tableau -
PG::Error: ERROR: index row size 3480 exceeds maximum 2712 for index "ix_data"
Voici ma définition de table -
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);
J'ai besoin d'un index sur le champ du tableau, car je fais des recherches dessus.
data
contienne une liste de balises comme démontré dans ce billet de blog connexe de Scott Snyder ? Si tel est le cas, je pourrais avoir une meilleure solution pour vous.Réponses:
Le problème
Voici un cas très similaire discuté sur pgsql.general . Il s'agit de la limitation dans un index b-tree, mais c'est la même chose car un index GIN utilise un index b-tree pour les clés en interne et se heurte donc à la même limitation pour la taille de la clé (au lieu de la taille de l' élément dans un b-tree ordinaire indice).
Je cite le manuel sur la mise en œuvre de l'index GIN :
Dans tous les cas, au moins un élément de tableau de votre colonne
data
est trop grand pour être indexé. S'il ne s'agit que d'une valeur singulière ou d'un accident, vous pourrez peut-être tronquer la valeur et en finir avec elle.Pour les besoins de la démo suivante, je vais supposer le contraire: beaucoup de longues valeurs de texte dans le tableau.
Solution simple
Vous pouvez remplacer les éléments de votre tableau
data
par des valeurs de hachage correspondantes . Et envoyez des valeurs de recherche via la même fonction de hachage. Bien sûr, vous voudrez probablement stocker vos originaux en plus quelque part. Avec cela, nous arrivons presque à ma deuxième variante ...Solution avancée
Vous pouvez créer une table de correspondance pour les éléments du tableau avec une
serial
colonne comme clé primaire de substitution (en fait un type radical de valeur de hachage) - ce qui est d'autant plus intéressant si les valeurs des éléments impliqués ne sont pas uniques:Puisque nous voulons rechercher
elem
, nous ajoutons un index - mais un index sur une expression cette fois, avec seulement les 10 premiers caractères du texte long. Cela devrait suffire dans la plupart des cas pour limiter la recherche à un ou à quelques résultats. Adaptez la taille à votre distribution de données. Ou utilisez une fonction de hachage plus sophistiquée.Votre colonne
data
serait alors de typeint[]
. J'ai renommé la tabledata
et je me suis débarrassé du sinistre quevarchar(50)
vous aviez dans votre exemple:Chaque élément du tableau
data
fait référence à aelem.elem_id
. À ce stade, vous pouvez envisager de remplacer la colonne du tableau par une table n: m, normalisant ainsi votre schéma et permettant à Postgres d'appliquer l'intégrité référentielle. L'indexation et la manipulation générale deviennent plus faciles ...Cependant, pour des raisons de performances, la
int[]
colonne associée à un indice GIN peut être supérieure. La taille de stockage est beaucoup plus petite. Dans ce cas, nous avons besoin de l'indice GIN:Maintenant, chaque clé de l'index GIN (= élément de tableau) est un
integer
au lieu d'un longishtext
. L'indice sera plus petit de plusieurs ordres de grandeur, les recherches seront donc beaucoup plus rapides.L'inconvénient: avant de pouvoir effectuer une recherche, vous devez rechercher le
elem_id
dans le tableauelem
. En utilisant mon index fonctionnel nouvellement introduitelem_elem_left10_idx
, cela aussi sera beaucoup plus rapide.Vous pouvez tout faire en une seule requête :
Vous pouvez être intéressé par l'extension
intarray
, qui fournit des opérateurs et des classes d'opérateurs supplémentaires.Démo en direct entièrement fonctionnelle sur sqlfiddle.
la source
L'erreur concerne l'index
ix_data
, pas letext[]
champ. La taille maximale d'une ligne dans ce type d'index particulier est limitée à des2712
octets. Si vous supprimez votre index et réessayez l'insertion, cela devrait fonctionner pour vous. Si vous devez indexer un champ plus grand, vous souhaiterez peut-être examiner les fonctionnalités d'indexation de texte intégral de postgres.la source
J'obtenais ceci sur une colonne de géographie de PostGIS. C'est parce que j'ai accidentellement créé l'index de manière incorrecte. Vous devez inclure le paramètre USING GIST lors de la création de tels index.
la source