Eu tenho uma tabela com 50 mil linhas. Na verdade, é uma tabela PostGIS.
A consulta possui 4 partes (1 obrigatória) (3 opcional)
- caixa de interseção (um retângulo geográfico) com 4 lat, comprimento (eu uso st_intersects) [Obrigatório]
- Período (mínimo, máximo) em um campo de data
- 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.
- 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.
- 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.
- Tudo o que eu estava procurando era algumas dicas, dicas e orientações.
- Li esta excelente publicação: https://devcenter.heroku.com/articles/postgresql-indexes#managing-and-maintaining-indexes sobre índices
- 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)
- 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.
- À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.
- 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.
- Se eu criar alguns índices compostos ou de valor único adicionais, o planejador é inteligente o suficiente para escolher o mais inteligente ...
- 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.
- 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'))
fonte
EXPLAIN ANALYZE
para a consulta.Respostas:
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:
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 ();
fonte
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.
fonte