Ordem das colunas em um índice composto no PostgreSQL (e ordem de consulta)

9

Eu tenho uma tabela com 50 mil linhas. Na verdade, é uma tabela PostGIS.

A consulta possui 4 partes (1 obrigatória) (3 opcional)

  1. caixa de interseção (um retângulo geográfico) com 4 lat, comprimento (eu uso st_intersects) [Obrigatório]
  2. Período (mínimo, máximo) em um campo de data
  3. Tipo de arquivo (um conjunto de até 8 valores de texto) atualmente usando IN (.....), mas posso torná-lo uma tabela temporária, se necessário. Vejo que muitas pessoas não gostam do IN.
  4. País (um valor de texto).

Espero cerca de 100 - 4.000 linhas retornadas

Se eu criar um índice composto na tabela, qual coluna devo usar primeiro. O refinado é provavelmente o local (os dados estão espalhados pelo mundo). Atualmente, tenho-o como índice GIST.

Os outros índices seriam BTREE.

Minha intuição diz que use granulação fina e curso por último. Por exemplo, existem apenas cerca de 12 tipos de arquivos, o que seria um grande depósito para o índice.

O que dizem os gurus do PostgreSQL e do PostGIS (que conhecem os aspectos internos do sistema)?


ATUALIZAR:

Deixe-me aprofundar esta questão.

  1. Não quero que ninguém precise fazer o trabalho que devo fazer. Eu respeito demais o seu tempo. Então, irei explicar mais tarde.
  2. Tudo o que eu estava procurando era algumas dicas, dicas e orientações.
  3. Li esta excelente publicação: https://devcenter.heroku.com/articles/postgresql-indexes#managing-and-maintaining-indexes sobre índices
  4. O que normalmente faço é criar 4 índices separados (caixa geográfica, nome do país, tipo de arquivo e data), mas o que deseja ver o que uma consulta composta faria.

Diga-me se alguma dessas suposições está errada. (Eu sou bastante novo na idéia de índices compostos)

  1. A ordem é importante. Escolha como o primeiro índice o que cortará mais as linhas (no meu caso, a localização (geografia), que é um polígono simples ou multi-polígono, faria melhor.
  2. Às vezes, as consultas ignoram os índices. Porém, se eu criar uma consulta composta com a chave (nº 1, nº 2, nº 3 e nº 4), mesmo que o usuário crie algo que solicite nº 1 e nº 3, o planejador ainda utilizará a única consulta composta, uma vez que solicita é mantido.
  3. Normalmente, eu criaria três consultas BTREE e uma GIST (para o tipo de região). O PostGIS não suporta a criação de um composto de vários tipos de índice. Então eu vou ter que usar GIST o índice composto. Mas isso não deve prejudicar as coisas.
  4. Se eu criar alguns índices compostos ou de valor único adicionais, o planejador é inteligente o suficiente para escolher o mais inteligente ...
  5. O nome do país pode ter cerca de 250 valores diferentes e obviamente está fortemente vinculado à localização (geobox), mas se o próximo melhor índice para reduzir o tamanho da linha for file_type, devo usá-lo em seguida. Não espero que os usuários usem frequentemente o país ou a data em seus conjuntos de consultas.
  6. Eu não preciso me preocupar em criar um índice composto de 4 chaves para aumentar muito o tamanho dos dados do índice. Ou seja, se um índice de uma tecla representaria 90% do aumento de desempenho, não custa acrescentar mais três itens para torná-lo composto. Por outro lado, eu realmente deveria criar os dois índices. Um índice de geografia única, e também um índice composto, e deixe o planejador descobrir qual é o melhor e ele levará em consideração o tamanho da tabela de índices.

Mais uma vez, não estou pedindo a ninguém para projetar minha solução, não discuto o trabalho de outras pessoas. Mas eu preciso de coisas que a documentação do PostGreSQL não me diz sobre implementação

[O motivo pelo qual ainda não tenho um resultado EXPLAIN para mostrar é que tenho que criar essa tabela de 25K linhas a partir de uma tabela de 24 milhões de linhas. Está demorando mais tempo do que eu pensava. Estou agrupando coisas em 1.000 grupos de itens e deixando o usuário consultar a tabela de linhas de 25K. Mas minha próxima pergunta, envolverá o uso dos resultados dessa consulta para ir para a tabela de linhas MASTER 25M e extrair as coisas, e é aí que o desempenho do índice composto realmente atingirá].


exemplo de consulta abaixo:


SELECT
    public.product_list_meta_mv.cntry_name       AS country,
    public.product_list_meta_mv.product_producer AS producer,
    public.product_list_meta_mv.product_name     AS prod_name,
    public.product_list_meta_mv.product_type     AS ptype,
    public.product_list_meta_mv.product_size     AS size,
    ST_AsGeoJSON(public.product_list_meta_mv.the_geom, 10, 2)          AS outline
FROM
    public.product_list_meta_mv 
WHERE
    public.product_list_meta_mv.cntry_name = 'Poland' 
AND
    ST_Intersects(public.product_list_meta_mv.the_geom,
    st_geogfromtext('SRID=4326;POLYGON((21.23107910156250 51.41601562500000,
                                        18.64379882812500 51.41601562500000,
                                        18.64379882812500 48.69415283203130,
                                        21.23107910156250 48.69415283203130,
                                        21.23107910156250 51.41601562500000))')) 
AND (date >= '1/2/1900 5:00:00 AM' 
 AND date <= '2/26/2014 10:26:44 PM')
AND (public.product_list_meta_mv.product_type in
    ('CIB10','DTED0','DTED1','DTED2','CIB01','CIB05')) ;

EXPLICAR ANALISAR resultados (não coloquei nenhum índice composto e, pela velocidade que vejo, não sei se preciso).

"Bitmap Heap Scan on catalog_full cat  (cost=4.33..37.49 rows=1 width=7428) (actual time=1.147..38.051 rows=35 loops=1)"
"  Recheck Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"  Filter: (((type)::text = ANY ('{CADRG,CIB10,DTED1,DTED2}'::text[])) AND (_st_distance('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography, outline, 0::double precision, false) < 1e-005::double precision))"
"  Rows Removed by Filter: 61"
"  ->  Bitmap Index Scan on catalog_full_outline_idx  (cost=0.00..4.33 rows=8 width=0) (actual time=0.401..0.401 rows=96 loops=1)"
"        Index Cond: ('0103000020E61000000100000005000000000000005838354000000000AEB0494000000000A0A7324000000000AEB0494000000000A0A73240000000006C5D48400000000058383540000000006C5D4840000000005838354000000000AEB04940'::geography && outline)"
"Total runtime: 38.109 ms"

EXPLAIN ANALYZE SELECT pid,product_name,type,country,date,size,cocom,description,egpl_date,ST_AsGeoJSON(outline, 10, 2) AS outline 
FROM portal.catalog_full AS cat 
WHERE ST_Intersects(st_geogfromtext('SRID=4326;POLYGON((21.2200927734375 51.38031005859375, 18.65478515625 51.38031005859375, 18.65478515625 48.7298583984375, 21.2200927734375 48.7298583984375, 21.2200927734375 51.38031005859375))'), cat.outline) 
AND (cat.type in ('CADRG','CIB10','DTED1','DTED2'))
Dr.YSG
fonte
2
Forneça a consulta real, por favor.
ypercubeᵀᴹ
O "3 opcional" significa que a consulta pode ter 8 variações diferentes (dependendo se as opções 2,3,4 estão ativadas ou não)?
ypercubeᵀᴹ
Existem 4 componentes AND no WHERE. No st_intersects é necessário, os outros podem estar lá ou não. Mas eu quero lidar com o caso em que eles estão todos presentes.
2
Votei em migrar a pergunta para o dba.se. Esta é uma consulta complexa com várias condições de intervalo.
ypercubeᵀᴹ
11
Mostrar EXPLAIN ANALYZEpara a consulta.
Craig Ringer

Respostas:

4

Como parte do meu trabalho, mantenho um banco de dados PostgreSQL bastante grande (cerca de 120 GB em disco, várias tabelas de vários milhões de linhas) e coletei alguns truques sobre como acelerar as consultas. Primeiro, alguns comentários sobre suas suposições:

  1. Sim, a ordem é importante, mas é apenas a primeira realmente diferente; o restante são índices de segunda classe.
  2. Não tenho certeza se ele sempre usará os dois, meu palpite é que o planejador de consultas usará o número 1 e fará algo inteligente com o resto.
  3. Não tenho experiência com GIST.
  4. Sim, adicione todos os índices primeiro, veja o que é mais usado e o que oferece o melhor desempenho.
  5. Eu sugiro que você tente os dois e meça o que funciona melhor. Tente reescrever o sql com subconsultas diferentes, talvez país e hora em um, depois junte-se à consulta de interseção. Não notei nenhum problema de desempenho com as cláusulas IN, desde que a lista IN não tenha milhares de elementos. Meu palpite é que algumas consultas diferentes ajustadas especificamente, dependendo dos critérios de entrada disponíveis, fornecerão os melhores resultados.
  6. Eu sugeriria não criar um índice de quatro direções. Tente criar um e, em seguida, verifique o tamanho, eles podem ficar realmente enormes. Na minha experiência, quatro índices de 1 tecla foram quase tão rápidos quanto um único índice de 4 vias. Um truque que funciona bem para algumas consultas específicas são índices parciais, ou seja, algo como isto:

    CRIAR INDEX ON table_x (chave1, chave2, chave3) WHERE some_x_column = 'XXXX';

Criei aliases no meu arquivo .psqlrc com consultas para ajudar a encontrar quais índices adicionar ou remover. Sinta-se livre para dar uma olhada neles no GitHub: .psql

Eu uso muito o: seq_scans e: bigtables e, em seguida, \ d table_name para obter detalhes sobre a tabela. Não se esqueça de redefinir as estatísticas depois de fazer algumas alterações, selecione pg_stat_reset ();

Claes Mogren
fonte
11
Essas são dicas excelentes. Eu segui seu conselho e, em seguida, usei isso para fazer um experimento em uma tabela muito maior que mantemos (43 milhões de linhas). Os resultados estão em: dba.stackexchange.com/questions/61084/…
Dr.YSG
1

Eu acho que a coisa mais provável para ajudar (se houver) seria adicionar product_type como uma segunda coluna ao índice de essência. Mas, sem saber quantas linhas correspondem a cada uma das condições AND (isoladamente) para suas consultas típicas / problemáticas, podemos apenas adivinhar.

Quando abordo isso, a primeira coisa que faço é executar a consulta de forma simplificada, em que a cláusula WHERE possui apenas uma condição, cada uma por sua vez, em EXPLAIN ANALYZE. Observe as linhas estimadas e as linhas reais de cada uma.

jjanes
fonte
veja minha atualização acima, mas acho que você está me dando uma boa vantagem, pense em ordenar os índices pelos quais reduz a saída da linha mais rapidamente. Isso está certo?
precisa saber é