PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Criando índices que não diferenciam maiúsculas de minúsculas no array de strings do Postgres


@Saurabh Nanda:Semelhante ao que você postou, você também pode criar uma função simples para converter sua matriz varchar em minúsculas da seguinte maneira:
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;

Observe que também estou cortando as tags de espaços. Isso pode não ser necessário para você, mas eu costumo fazer por consistência.

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

Conforme observado por Saurabh, você pode criar um índice GIN:
CREATE INDEX ix_tags ON tagtable USING GIN(array_lowercase(tags));

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

ATUALIZAÇÃO: Desempenho de WHILE vs array_agg/unnest

Eu criei uma tabela de 100K 10 elemento text[] arrays (sequências de maiúsculas e minúsculas aleatórias de 12 caracteres) e testou cada função.

A função array_agg/unnest retornou:
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)

A função WHILE retornou:
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)

ATUALIZAÇÃO 2: FOREACH vs. WHILE Como experimento final, alterei a função WHILE para usar 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'

Os resultados parecem ser semelhantes a 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)

Embora meus testes não sejam de forma alguma rigorosos, executei cada versão várias vezes e achei os números representativos, sugerindo que o método SQL (array_agg/unnest) é o mais rápido.