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

Otimização de consultas no PostgreSQL. EXPLIQUE Noções básicas - Parte 3


Continuo uma série de artigos sobre os fundamentos do EXPLAIN no PostgreSQL, que é uma breve revisão de Understanding EXPLAIN de Guillaume Lelarge.
Para entender melhor o assunto, recomendo rever o original “Understanding EXPLAIN” de Guillaume Lelarge e leia meu primeiro e segundo artigos.



ORENDER POR
DROP INDEX foo_c1_idx;
EXPLAIN (ANALYZE) SELECT * FROM foo ORDER BY c1;



Primeiramente, você executa uma varredura sequencial (Seq Scan) da tabela foo e, em seguida, faz a ordenação (Sort). O sinal -> do comando EXPLAIN indica a hierarquia das etapas (nó). Quanto mais cedo a etapa for executada, maior será o recuo.

Chave de classificação é uma condição de classificação.

Sort Method:External merge Disk um arquivo temporário no disco com capacidade de 4592 kB é usado na ordenação.
Verifique com a opção BUFFERS:
DROP INDEX foo_c1_idx;
EXPLAIN (ANALYZE) SELECT * FROM foo ORDER BY c1;



De fato, a linha temp read=5745 write=5745 significa que 45960Kb (5745 blocos de 8 Kb cada) foram armazenados e lidos no arquivo temporário. As operações com 8334 blocos foram executadas no cache.

As operações com o sistema de arquivos são mais lentas do que as operações na RAM.

Vamos tentar aumentar a capacidade de memória do work_mem:
SET work_mem TO '200MB';
EXPLAIN (ANALYZE) SELECT * FROM foo ORDER BY c1;



Método de Ordenação:quicksort Memória:102702kB – toda a ordenação foi executada na RAM.
O índice é o seguinte:
CREATE INDEX ON foo(c1);
EXPLAIN (ANALYZE) SELECT * FROM foo ORDER BY c1;



Temos apenas Index Scan restante, o que afetou significativamente a velocidade da consulta.

LIMITE


Exclua o índice criado anteriormente:
DROP INDEX foo_c2_idx1;
EXPLAIN (ANALYZE,BUFFERS)
  SELECT * FROM foo WHERE c2 LIKE 'ab%';



Como esperado, Seq Scan e Filter são usados.
EXPLAIN (ANALYZE,BUFFERS)
SELECT * FROM foo WHERE c2 LIKE 'ab%' LIMIT 10;



Seq Scan lê as linhas da tabela e as compara (Filter) com a condição. Assim que houver 10 registros que atendam à condição, a verificação será encerrada. No nosso caso, para obter 10 linhas de resultado, tivemos que ler apenas 3063 registros em vez de toda a tabela. 3053 linhas deste número foram rejeitadas (Linhas Removidas pelo Filtro).
O mesmo acontece com o Index Scan.

PARTICIPE


Crie uma nova tabela e gere estatísticas para ela:
CREATE TABLE bar (c1 integer, c2 boolean);
INSERT INTO bar
  SELECT i, i%2=1
  FROM generate_series(1, 500000) AS i;
ANALYZE bar;

A consulta para duas tabelas é a seguinte:
EXPLAIN (ANALYZE)
SELECT * FROM foo JOIN bar ON foo.c1=bar.c1;



Primeiro, a varredura sequencial (Seq Scan) lê a tabela de barras. Um hash (Hash) é calculado para cada linha.

Em seguida, ele varre a tabela foo e, para cada linha, é calculado um hash que é comparado (Hash Join) com o hash da tabela bar pela condição Hash Cond. Se eles corresponderem, uma string resultante será emitida.

18067kB de memória são usados ​​para armazenar hashes para a barra.

Adicione o índice:
CREATE INDEX ON bar(c1);
EXPLAIN (ANALYZE)
SELECT * FROM foo JOIN bar ON foo.c1=bar.c1;



Hash não é mais usado. Merge Join e Index Scan nos índices de ambas as tabelas melhoram muito o desempenho.

LEFT JOIN:
EXPLAIN (ANALYZE)
SELECT * FROM foo LEFT JOIN bar ON foo.c1=bar.c1;



Seq Scan?

Vamos ver qual resultado teremos se desabilitarmos o Seq Scan.
SET enable_seqscan TO off; 
EXPLAIN (ANALYZE)
SELECT * FROM foo LEFT JOIN bar ON foo.c1=bar.c1;



De acordo com o escalonador, usar índices é mais caro do que usar hashes. Isso é possível com uma quantidade suficientemente grande de memória alocada. Você se lembra de nós aumentando work_mem?

No entanto, se você não tiver memória suficiente, o agendador se comportará de maneira diferente:
SET work_mem TO '15MB';
SET enable_seqscan TO ON; 
EXPLAIN (ANALYZE)
SELECT * FROM foo LEFT JOIN bar ON foo.c1=bar.c1;



Se desabilitarmos a Varredura de Índice, qual resultado EXPLAIN será exibido?
SET work_mem TO '15MB';
SET enable_indexscan TO off; 
EXPLAIN (ANALYZE)
SELECT * FROM foo LEFT JOIN bar ON foo.c1=bar.c1;



Lotes:2 aumentou o custo. O hash inteiro não coube na memória; tivemos que dividi-lo em dois pacotes de 9045kB.

Obrigado por ler meus artigos! Espero que tenham sido úteis. Se você tiver algum comentário ou feedback, sinta-se à vontade para me informar.