PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Création d'index insensibles à la casse sur le tableau de chaînes Postgres

@Saurabh Nanda :Semblable à ce que vous avez publié, vous pouvez également créer une fonction simple pour convertir votre tableau varchar en minuscules comme suit :

CREATE OR REPLACE FUNCTION array_lowercase(varchar[]) RETURNS varchar[] AS
$BODY$
  SELECT array_agg(q.tag) FROM (
    SELECT btrim(lower(unnest($1)))::varchar AS tag
  ) AS q;
$BODY$
  language sql IMMUTABLE;

Notez que je coupe également les balises des espaces. Cela n'est peut-être pas nécessaire pour vous, mais je le fais généralement par souci de cohérence.

Test :

SELECT array_lowercase(array['Hello','WOrLD']);
 array_lowercase 
-----------------
 {hello,world}
(1 row)

Comme l'a noté Saurabh, vous pouvez ensuite créer un index GIN :

CREATE INDEX ix_tags ON tagtable USING GIN(array_lowercase(tags));

Et requête :

SELECT * FROM tagtable WHERE ARRAY['mytag'::varchar] && array_lowercase(tags);

MISE À JOUR : Performances de WHILE vs array_agg/unnest

J'ai créé une table de 100K 10 éléments text[] tableaux (chaînes aléatoires de 12 caractères à casse mixte) et testé chaque fonction.

La fonction array_agg/unnest a renvoyé :

EXPLAIN ANALYZE VERBOSE SELECT array_lowercase(data) FROM test;
                                                       QUERY PLAN                                                       
------------------------------------------------------------------------------------------------------------------------
 Seq Scan on public.test  (cost=0.00..28703.00 rows=100000 width=184) (actual time=0.320..3041.292 rows=100000 loops=1)
   Output: array_lowercase((data)::character varying[])
 Total runtime: 3174.690 ms
(3 rows)

La fonction TANTQUE a renvoyé :

EXPLAIN ANALYZE VERBOSE SELECT array_lowercase_while(data) FROM test;
                                                       QUERY PLAN                                                       
------------------------------------------------------------------------------------------------------------------------
 Seq Scan on public.test  (cost=0.00..28703.00 rows=100000 width=184) (actual time=5.128..4356.647 rows=100000 loops=1)
   Output: array_lowercase_while((data)::character varying[])
 Total runtime: 4485.226 ms
(3 rows)

MISE À JOUR 2 : FOREACH vs WHILE Comme expérience finale, j'ai changé la fonction WHILE pour utiliser FOREACH :

CREATE OR REPLACE FUNCTION array_lowercase_foreach(p_input varchar[]) RETURNS varchar[] AS $BODY$
DECLARE
    el text;
    r varchar[];
BEGIN
    FOREACH el IN ARRAY p_input LOOP
        r := r || btrim(lower(el))::varchar;
    END LOOP;
    RETURN r;
END;
$BODY$
  language 'plpgsql'

Les résultats semblent être similaires à WHILE :

EXPLAIN ANALYZE VERBOSE SELECT array_lowercase_foreach(data) FROM test;
                                                       QUERY PLAN                                                       
------------------------------------------------------------------------------------------------------------------------
 Seq Scan on public.test  (cost=0.00..28703.00 rows=100000 width=184) (actual time=0.707..4106.867 rows=100000 loops=1)
   Output: array_lowercase_foreach((data)::character varying[])
 Total runtime: 4239.958 ms
(3 rows)

Bien que mes tests ne soient en aucun cas rigoureux, j'ai exécuté chaque version plusieurs fois et j'ai trouvé que les chiffres étaient représentatifs, ce qui suggère que la méthode SQL (array_agg/unnest) est la plus rapide.