Je vais essayer d'expliquer mes malentendus par l'exemple suivant.
Je ne comprenais pas fondamentaux du Bitmap Heap Scan Node
. Considérez la requête SELECT customerid, username FROM customers WHERE customerid < 1000 AND username <'user100';
dont le plan est le suivant:
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)
Ma compréhension de ce nœud:
Comme expliqué là , le bitmap heap scan
lit les blocs de table dans un ordre séquentiel, donc il ne produit pas de surcharge d'accès à la table aléatoire, ce qui se produit en faisant simplement Index Scan
.
Après Index Scan
a été fait, PostgreSQL ne sait pas comment récupérer les lignes de manière optimale, pour éviter les inutiles heap blocks reads
(ou hits
s'il y a un cache actif). Donc, pour le comprendre, il génère la structure (Bitmap Index Scan
) appelé bitmap
qui dans mon cas est généré en générant deux bitmaps des index et en exécutant BITWISE AND
. Puisque le bitmap a été généré, il peut maintenant lire le tableau de manière optimale dans un ordre séquentiel, évitant ainsi heap I/O-operations
.
C'est l'endroit où beaucoup de questions se posent.
QUESTION: Nous avons juste un bitmap. Comment PostgreSQL sait-il par un simple bitmap quoi que ce soit sur l'ordre physique des lignes? Ou génère le bitmap afin que tout élément de celui-ci puisse être mappé facilement au pointeur vers une page? Si c'est le cas, cela explique tout, mais c'est juste ma supposition.
Alors, peut-on dire simplement que le bitmap heap scan -> bitmap index scan
est comme un scan séquentiel mais seulement de la partie appropriée du tableau?
Comment PostgreSQL sait-il par un simple bitmap quoi que ce soit sur l'ordre physique des lignes?
Le bitmap est un bit par page de tas. L'analyse d'index bitmap définit les bits en fonction de l'adresse de la page de segment de mémoire vers laquelle pointe l'index.
Donc, quand il va faire le scan de tas de bitmap, il fait juste un scan de table linéaire, lisant le bitmap pour voir s'il doit s'embêter avec une page particulière ou chercher dessus.
Ou génère le bitmap afin que tout élément de celui-ci puisse être mappé facilement au pointeur vers une page?
Non, le bitmap correspond à 1: 1 aux pages de tas.
J'ai écrit un peu plus à ce sujet ici .
OK, il semble que vous ne compreniez pas bien ce que signifie "bitmap" dans ce contexte.
Ce n'est pas une chaîne de bits comme "101011" qui est créée pour chaque page de tas, ou chaque index lu, ou autre chose.
L'ensemble du bitmap est un seul tableau de bits , avec autant de bits qu'il y a de pages de segment dans la relation en cours d'analyse.
Un bitmap est créé par le premier balayage d'index, en commençant par toutes les entrées 0 (faux). Chaque fois qu'une entrée d'index correspondant à la condition de recherche est trouvée, l'adresse de segment pointée par cette entrée d'index est recherchée comme un décalage dans le bitmap, et ce bit est défini sur 1 (vrai). Ainsi, plutôt que de rechercher directement la page de tas, l'analyse d'index bitmap recherche la position de bit correspondante dans le bitmap.
Le deuxième et les autres analyses d'index bitmap font la même chose avec les autres index et les conditions de recherche sur eux.
Ensuite, chaque bitmap est AND ensemble. Le bitmap résultant a un bit pour chaque page de segment de mémoire, où les bits ne sont vrais que s'ils étaient vrais dans tous les scans d'index bitmap individuels, c'est-à-dire que la condition de recherche correspond à chaque scan d'index. Ce sont les seules pages de tas que nous devons prendre la peine de charger et d'examiner. Étant donné que chaque page de tas peut contenir plusieurs lignes, nous devons ensuite examiner chaque ligne pour voir si elle correspond à toutes les conditions - c'est à cela que sert la partie "revérifier la condition".
Une chose cruciale à comprendre avec tout cela est que l'adresse de tuple dans une entrée d'index pointe vers le ctid
de la ligne, qui est une combinaison du numéro de page du tas et du décalage dans la page du tas. Un scan d'index bitmap ignore les décalages, car il vérifiera de toute façon la page entière et définit le bit si une ligne de cette page correspond à la condition.
Exemple graphique
Heap, one square = one page:
+---------------------------------------------+
|c____u_____X___u___X_________u___cXcc______u_|
+---------------------------------------------+
Rows marked c match customers pkey condition.
Rows marked u match username condition.
Rows marked X match both conditions.
Bitmap scan from customers_pkey:
+---------------------------------------------+
|100000000001000000010000000000000111100000000| bitmap 1
+---------------------------------------------+
One bit per heap page, in the same order as the heap
Bits 1 when condition matches, 0 if not
Bitmap scan from ix_cust_username:
+---------------------------------------------+
|000001000001000100010000000001000010000000010| bitmap 2
+---------------------------------------------+
Une fois les bitmaps créés, un ET au niveau du bit est exécuté sur eux:
+---------------------------------------------+
|100000000001000000010000000000000111100000000| bitmap 1
|000001000001000100010000000001000010000000010| bitmap 2
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
|000000000001000000010000000000000010000000000| Combined bitmap
+-----------+-------+--------------+----------+
| | |
v v v
Used to scan the heap only for matching pages:
+---------------------------------------------+
|___________X_______X______________X__________|
+---------------------------------------------+
L'analyse du tas bitmap cherche ensuite au début de chaque page et lit la page:
+---------------------------------------------+
|___________X_______X______________X__________|
+---------------------------------------------+
seek------->^seek-->^seek--------->^
| | |
------------------------
only these pages read
et chaque page lue est ensuite revérifiée par rapport à la condition car il peut y avoir> 1 ligne par page et toutes ne correspondent pas nécessairement à la condition.
Veuillez consulter mon article de blog https://rajeevrastogi.blogspot.in/2018/02/bitmap-scan-in-postgresql.html?showComment=1518410565792#c4647352762092142586 pour plus de détails sur la description du scan bitmap dans PostgreSQL.
Aperçu général des fonctionnalités rapides du scan bitmap:
Bitmap Heap scan demande un tuple à partir de Bitmap Index Scan.
Bitmap Index Scan scanne l'index selon la condition presque de la même manière que dans le scan d'index normal. Mais au lieu de renvoyer le TID (composé du numéro de page et du décalage à l'intérieur de celui-ci) correspondant aux données du tas, il ajoute ces TID dans un bitmap. Pour une compréhension simple, vous pouvez considérer que ce bitmap contient le hachage de toutes les pages (haché en fonction du numéro de page) et chaque entrée de page contient un tableau de tous les décalages dans cette page.
Bitmap Heap Scan lit ensuite le bitmap pour obtenir les données de tas correspondant au numéro de page stocké et au décalage. Ensuite, il vérifie la visibilité, la qualification, etc. et renvoie le tuple en fonction des résultats de tous ces contrôles.