Je ne trouve pas de réponse définitive à cette question dans la documentation. Si une colonne est un type de tableau, toutes les valeurs entrées seront-elles indexées individuellement?
J'ai créé un tableau simple avec un int[]
colonne et mettez un index unique dessus. J'ai remarqué que je ne pouvais pas ajouter le même tableau d'ints, ce qui me porte à croire que l'index est un composite des éléments du tableau, pas un index de chaque élément.
INSERT INTO "Test"."Test" VALUES ('{10, 15, 20}');
INSERT INTO "Test"."Test" VALUES ('{10, 20, 30}');
SELECT * FROM "Test"."Test" WHERE 20 = ANY ("Column1");
Est-ce que l'index aide cette requête?
Oui, vous pouvez indexer un tableau, mais vous devez utiliser les opérateurs de tablea et le type d'index GIN .
Exemple:
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];
Résultat:
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
il semble que dans de nombreux cas, l'option gin__int_ops est requise
create index <index_name> on <table_name> using GIN (<column> gin__int_ops)
Je n'ai pas encore vu de cas où cela fonctionnerait avec l'opérateur && et @> sans les options gin__int_ops
@Tregoreg a soulevé un question dans le commentaire à sa prime offerte:
Je n'ai pas trouvé les réponses actuelles qui fonctionnent. L'utilisation de l'index GIN sur une colonne de type tableau n'augmente pas les performances de l'opérateur ANY (). N'y a-t-il vraiment pas de solution?
@ Frank est accepté réponse vous dit d'utiliser opérateurs de tableau , ce qui est toujours correct pour Postgres 11. The manual:
... la distribution standard de PostgreSQL inclut une classe d'opérateurs GIN pour les tableaux, qui prend en charge les requêtes indexées à l'aide de ces opérateurs:
<@ @> = &&
Dans Postgres , les index sont liés à des opérateurs (qui sont implémentés pour certains types), pas à des types de données ni à des fonctions ou quoi que ce soit d'autre. C’est un héritage du design original de Postgres à Berkeley et très difficile à changer maintenant. Et cela fonctionne généralement très bien. Voici un fil sur pgsql-bugs avec Tom Lane en commentant.
Certains PostGis fonctions (comme ST_DWithin()
) semblent violer ce principe, mais ce n'est pas le cas. Ces fonctions sont réécrites en interne pour utiliser les opérateurs opérateurs respectifs.
L'expression indexée doit être à l'opérateur left. Pour la plupart des opérateurs ( y compris tout ce qui précède), le planificateur de requêtes peut y parvenir en retournant des opérandes si vous placez l'expression indexée à droite - étant donné qu'un COMMUTATOR
a été défini. Le ANY
construct peut être utilisé en combinaison avec différents opérateurs et n’est pas un opérateur lui-même. Lorsqu'il est utilisé en tant que constant = ANY (array_expression)
, seuls les index prenant en charge l'opérateur =
Sur éléments de tableau seraient admissibles et nous aurions besoin d'un commutateur pour = ANY()
. Les index GIN sont sortis.
Actuellement, Postgres n'est pas assez intelligent pour en tirer une expression indexable GIN. Pour commencer, constant = ANY (array_expression)
n'est pas totalement équivalent à array_expression @> ARRAY[constant]
. Les opérateurs de tableaux renvoient une erreur si des éléments NULL éléments sont impliqués, alors que la construction ANY
peut traiter NULL de chaque côté. Et il existe différents résultats pour les disparités de type de données.
Réponses associées:
SQLAlchemy: comment filtrer sur les types de colonnes PgArray?
Peut-on IS DISTINCT FROM être combiné avec TOUT ou TOUT d'une façon ou d'une autre??
Tout en travaillant avec integer
tableaux (int4
, Pas int2
Ou int8
) sans NULL
valeurs (comme votre exemple l’implique) considérons le module supplémentaire intarray
, qui fournit aux opérateurs spécialisés et plus rapides et au support des index. Voir:
En ce qui concerne la contrainte UNIQUE
de votre question qui est restée sans réponse: elle est implémentée avec un index btree sur la valeur tableau entier (comme vous le supposiez) et ne facilite pas la recherche de éléments du tout. Détails:
Il est maintenant possible d'indexer les différents éléments du tableau. Par exemple:
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)
Cela fonctionne au moins sur Postgres 9.2.1. Notez que vous devez créer un index distinct pour chaque index de tableau. Dans mon exemple, je n'ai indexé que le premier élément.