Linha "Verificar novamente Cond:" nos planos de consulta com uma verificação de índice de bitmap

21

Esta é uma derivação dos comentários para a pergunta anterior:

Usando o PostgreSQL 9.4, sempre parece haver uma Recheck Cond:linha após as verificações do índice de bitmap nos planos de consulta gerados por EXPLAIN.

Como na EXPLAINsaída da pergunta referenciada:

->  Bitmap Heap Scan on table_three  (cost=2446.92..19686.74 rows=8159 width=7)
      Recheck Cond: (("timestamp" > (now() - '30 days'::interval)) AND (client_id > 0))
      ->  BitmapAnd  (cost=2446.92..2446.92 rows=8159 width=0)
            ->  Bitmap Index Scan on table_one_timestamp_idx  (cost=0.00..1040.00 rows=79941 width=0)
                  Index Cond: ("timestamp" > (now() - '30 days'::interval))
            ->  Bitmap Index Scan on fki_table_three_client_id  (cost=0.00..1406.05 rows=107978 width=0)
                  Index Cond: (client_id > 0)

Ou no resultado de EXPLAIN ANALYZEuma tabela simples e enorme (com muito pouco work_mem):

EXPLAIN ANALYZE SELECT * FROM aa WHERE a BETWEEN 100000 AND 200000;
Bitmap Heap Scan on aa  (cost=107.68..4818.05 rows=5000 width=4) (actual time=27.629..213.606 rows=100001 loops=1)
  Recheck Cond: ((a >= 100000) AND (a <= 200000))
  Rows Removed by Index Recheck: 758222
  Heap Blocks: exact=693 lossy=3732
  ->  Bitmap Index Scan on aai  (cost=0.00..106.43 rows=5000 width=0) (actual time=27.265..27.265 rows=100001 loops=1)
        Index Cond: ((a >= 100000) AND (a <= 200000))

Isso significa que as condições do índice precisam ser verificadas uma segunda vez após uma verificação de índice de bitmap?
O que mais podemos aprender com a EXPLAINsaída?

Erwin Brandstetter
fonte

Respostas:

17

Como o @Chris comentou corretamente sobre a pergunta referenciada :

uma pequena investigação parece indicar que a condição de verificação novamente é sempre impressa no EXPLAIN, mas na verdade só é executada quando work_memé pequena o suficiente para que o bitmap fique com perda. Pensamentos? http://www.postgresql.org/message-id/[email protected]

Embora tudo isso seja verdade e o desenvolvedor principal Heikki Linnakangas seja uma fonte de primeira classe, o post data de 2007 (Postgres 8.2). Aqui está um post de Michael Paquier com explicação detalhada para o Postgres 9.4 , onde a saída de EXPLAIN ANALYZEfoi aprimorada com mais informações.

A Recheck Cond:linha está sempre lá para verificações de índice de bitmap. A saída do básico EXPLAINnão nos dirá mais. Obtemos informações adicionais, EXPLAIN ANALYZEcomo pode ser visto na segunda citação na pergunta:

Heap Blocks: exact=693 lossy=3732

De um total de 4425 páginas de dados (blocos), 693 tuplas armazenaram exatamente (incluindo ponteiros de tupla), enquanto as outras 3732 páginas estavam com perdas (apenas a página de dados) no bitmap. Isso acontece quando work_memnão é grande o suficiente para armazenar exatamente todo o bitmap criado a partir da varredura de índice (sem perdas).

A condição do índice deve ser verificada novamente para as páginas do compartilhamento com perdas, pois o bitmap lembra apenas quais páginas buscar e não as tuplas exatas na página. Nem todas as tuplas da página necessariamente passam nas condições do índice, é necessário realmente verificar novamente a condição.

Este é o tópico dos hackers pgsql onde a nova adição foi discutida . O autor Etsuro Fujita fornece uma fórmula sobre como calcular o mínimo work_mempara evitar entradas de bitmap com perdas e checagens de condições subsequentes. O cálculo não é confiável para casos complexos com várias varreduras de bitmap; portanto, não foi usado para gerar números reais EXPLAIN. Ainda pode servir como uma estimativa para casos simples.

Linha adicional BUFFERS:

Além disso, ao executar com a BUFFERSopção: EXPLAIN (ANALYZE, BUFFERS) ...outra linha é adicionada como:

Buffers: shared hit=279 read=79

Isso indica quanto da tabela (e índice) subjacente foi lida no cache ( shared hit=279) e quanto precisou ser buscado no disco ( read=79). Se você repetir a consulta, a parte "ler" normalmente desaparece para consultas não muito grandes, porque tudo é armazenado em cache agora após a primeira chamada. A primeira chamada informa quanto já foi armazenado em cache. As chamadas subseqüentes mostram quanto seu cache pode suportar (atualmente).

Existem mais opções. O manual sobre a BUFFERSopção:

Especificamente, inclua o número de blocos compartilhados atingidos, lidos, sujos e gravados, o número de blocos locais atingidos, lidos, sujos e gravados e o número de blocos temporários lidos e gravados.

Continue lendo, há mais.
Aqui está a lista de opções de saída no código fonte .

Erwin Brandstetter
fonte
10

Erwin, como essa foi a nossa discussão no tópico de comentários de antes, decidi cutucá-lo um pouco mais ...

Eu tenho uma consulta muito simples de uma tabela de tamanho razoável. Normalmente tenho o suficiente work_mem, mas nesse caso usei os comandos

SET work_mem = 64;

para definir um muito pequeno work_meme

SET work_mem = default;

para definir que minhas work_memcostas sejam suficientemente grandes para minha consulta.

EXPLIQUE e verifique novamente a condição

Então, executando minha consulta apenas EXPLAINcomo

EXPLAIN 
SELECT * FROM olap.reading_facts
WHERE meter < 20;

Eu obtive os resultados para baixo e alto work_mem:

Baixo work_mem

Bitmap Heap Scan on reading_facts  (cost=898.92..85632.60 rows=47804 width=32)
  Recheck Cond: (meter < 20)
  ->  Bitmap Index Scan on idx_meter_reading_facts  (cost=0.00..886.96 rows=47804 width=0)
        Index Cond: (meter < 20)

Alto work_mem

Bitmap Heap Scan on reading_facts  (cost=898.92..85632.60 rows=47804 width=32)
  Recheck Cond: (meter < 20)
  ->  Bitmap Index Scan on idx_meter_reading_facts  (cost=0.00..886.96 rows=47804 width=0)
        Index Cond: (meter < 20)

Para encurtar a história, EXPLAINapenas como esperado, o plano de consulta indica que uma condição Recheck é possível, mas não sabemos se será realmente calculado.

EXPLICAR ANALISAR & Verificar novamente a condição

Quando incluímos ANALYZEna consulta, os resultados nos dizem mais sobre o que precisamos saber.

Baixo work_mem

Bitmap Heap Scan on reading_facts  (cost=898.92..85632.60 rows=47804 width=32) (actual time=3.130..13.946 rows=51840 loops=1)
  Recheck Cond: (meter < 20)
  Rows Removed by Index Recheck: 86727
  Heap Blocks: exact=598 lossy=836
  ->  Bitmap Index Scan on idx_meter_reading_facts  (cost=0.00..886.96 rows=47804 width=0) (actual time=3.066..3.066 rows=51840 loops=1)
        Index Cond: (meter < 20)

Alto work_mem

Bitmap Heap Scan on reading_facts  (cost=898.92..85632.60 rows=47804 width=32) (actual time=2.647..7.247 rows=51840 loops=1)
  Recheck Cond: (meter < 20)
  Heap Blocks: exact=1434
  ->  Bitmap Index Scan on idx_meter_reading_facts  (cost=0.00..886.96 rows=47804 width=0) (actual time=2.496..2.496 rows=51840 loops=1)
        Index Cond: (meter < 20)

Mais uma vez, como esperado, a inclusão de ANALYZEnos revela algumas informações muito importantes. No work_memcaso baixo , vemos que há linhas removidas pela verificação do índice e que temos lossyblocos de heap.

Conclusão? (ou falta dela)

Infelizmente, parece que, EXPLAINpor si só, não é suficiente saber se uma verificação de índice será realmente necessária, porque alguns dos IDs de linha estão sendo descartados em favor da retenção de páginas durante a verificação de heap de bitmap.

Usar EXPLAIN ANALYZEé bom para diagnosticar os problemas com consultas de tamanho moderado, mas se uma consulta estiver demorando muito tempo para ser concluída, a execução EXPLAIN ANALYZEpara descobrir que o índice de bitmap está sendo convertido em perda por insuficiente work_memainda é uma restrição difícil. Eu gostaria que houvesse uma maneira de EXPLAINestimar a probabilidade dessa ocorrência a partir das estatísticas da tabela.

Chris
fonte