Vou tentar explicar meus mal-entendidos com o seguinte exemplo.
Não entendi os fundamentos do Bitmap Heap Scan Node
. Considere a consulta SELECT customerid, username FROM customers WHERE customerid < 1000 AND username <'user100';
cujo plano é este:
Bitmap Heap Scan on customers (cost=25.76..61.62 rows=10 width=13) (actual time=0.077..0.077 rows=2 loops=1)
Recheck Cond: (((username)::text < 'user100'::text) AND (customerid < 1000))
-> BitmapAnd (cost=25.76..25.76 rows=10 width=0) (actual time=0.073..0.073 rows=0 loops=1)
-> Bitmap Index Scan on ix_cust_username (cost=0.00..5.75 rows=200 width=0) (actual time=0.006..0.006 rows=2 loops=1)
Index Cond: ((username)::text < 'user100'::text)
-> Bitmap Index Scan on customers_pkey (cost=0.00..19.75 rows=1000 width=0) (actual time=0.065..0.065 rows=999 loops=1)
Index Cond: (customerid < 1000)
Minha compreensão deste nó :
Conforme explicado lá , os bitmap heap scan
blocos de tabela de leitura em ordem sequencial, portanto, não produz sobrecarga de acesso à tabela aleatória que acontece ao fazer apenas Index Scan
.
Depois Index Scan
de feito, o PostgreSQL não sabe como buscar as linhas de forma otimizada, para evitar o desnecessário heap blocks reads
(ou hits
se houver um hot cache). Então, para descobrir isso, ele gera a estrutura ( Bitmap Index Scan
) chamada bitmap
que no meu caso está sendo gerada gerando dois bitmaps dos índices e executando BITWISE AND
. Uma vez que o bitmap foi gerado, ele agora pode ler a tabela de forma otimizada em uma ordem sequencial, evitando arquivos desnecessários heap I/O-operations
.
Esse é o lugar onde muitas perguntas vêm.
PERGUNTA: Temos apenas um bitmap. Como o PostgreSQL sabe por apenas um bitmap qualquer coisa sobre a ordem física das linhas? Ou gera o bitmap para que qualquer elemento dele possa ser mapeado facilmente para o ponteiro de uma página? Se sim, isso explica tudo, mas é apenas minha suposição.
Então, podemos dizer simplesmente que bitmap heap scan -> bitmap index scan
é como uma varredura sequencial, mas apenas da parte apropriada da tabela?
O bitmap é um bit por página de heap. A varredura de índice de bitmap define os bits com base no endereço de página de heap para o qual a entrada de índice aponta.
Então, quando ele vai fazer a varredura de heap de bitmap, ele apenas faz uma varredura de tabela linear, lendo o bitmap para ver se ele deve se preocupar com uma página específica ou procurá-la.
Não, o bitmap corresponde 1:1 às páginas heap.
Eu escrevi um pouco mais sobre isso aqui .
OK, parece que você pode estar entendendo mal o que "bitmap" significa neste contexto.
Não é uma string de bits como "101011" que é criada para cada página de heap, ou cada leitura de índice, ou qualquer outra coisa.
O bitmap inteiro é um array de bit único , com tantos bits quantos as páginas de heap na relação que está sendo varrida.
Um bitmap é criado pela primeira varredura de índice, começando com todas as entradas 0 (falso). Sempre que uma entrada de índice que corresponde à condição de pesquisa é encontrada, o endereço de heap apontado por essa entrada de índice é pesquisado como um deslocamento no bitmap e esse bit é definido como 1 (verdadeiro). Portanto, em vez de procurar a página de heap diretamente, a varredura de índice de bitmap procura a posição de bit correspondente no bitmap.
A segunda e outras varreduras de índice de bitmap fazem a mesma coisa com os outros índices e as condições de pesquisa neles.
Em seguida, cada bitmap é combinado com AND. O bitmap resultante tem um bit para cada página de heap, onde os bits são verdadeiros somente se forem verdadeiros em todas as varreduras de índice de bitmap individuais, ou seja, a condição de pesquisa correspondida para cada varredura de índice. Essas são as únicas páginas de heap que precisamos nos preocupar em carregar e examinar. Como cada página de heap pode conter várias linhas, temos que examinar cada linha para ver se ela corresponde a todas as condições - é disso que trata a parte "recheck cond".
Uma coisa crucial para entender com tudo isso é que o endereço da tupla em uma entrada de índice aponta para o row's
ctid
, que é uma combinação do número da página de heap e o deslocamento dentro da página de heap. Uma varredura de índice de bitmap ignora os deslocamentos, pois verificará a página inteira de qualquer maneira e definirá o bit se qualquer linha dessa página corresponder à condição.Exemplo gráfico
Depois que os bitmaps são criados, um AND bit a bit é executado neles:
A varredura de heap de bitmap então procura o início de cada página e lê a página:
e cada página lida é então verificada novamente em relação à condição, pois pode haver > 1 linha por página e nem todas necessariamente correspondem à condição.
Consulte minha postagem no blog https://rajeevrastogi.blogspot.in/2018/02/bitmap-scan-in-postgresql.html?showComment=1518410565792#c4647352762092142586 para obter uma descrição detalhada da verificação de bitmap no PostgreSQL.
Visão geral geral da funcionalidade rápida da varredura de bitmap:
A varredura de heap de bitmap solicita uma tupla da varredura de índice de bitmap.
A Varredura de Índice de Bitmap varre o índice de acordo com a condição quase da mesma maneira que é feita na Varredura de Índice normal. Mas, em vez de retornar o TID (consistindo no número da página e o deslocamento dentro disso) correspondente aos dados do heap, ele adiciona esses TID em um bitmap. Para uma compreensão simples, você pode considerar que este bitmap contém hash de todas as páginas (hash com base no número da página) e cada entrada de página contém matriz de todos os deslocamentos nessa página.
Em seguida, o Bitmap Heap Scan lê o bitmap para obter dados de heap correspondentes ao número da página armazenada e ao deslocamento. Em seguida, ele verifica a visibilidade, qualificação etc. e retorna a tupla com base no resultado de todas essas verificações.