ทำความเข้าใจกับ“ การสแกนบิตแมปฮีป” และ“ การสแกนดัชนีบิตแมป”


36

ฉันจะพยายามอธิบายความเข้าใจที่คลาดเคลื่อนของฉันตามตัวอย่างต่อไปนี้

ผมไม่เข้าใจปัจจัยพื้นฐานBitmap Heap Scan Nodeของ พิจารณาแบบสอบถามSELECT customerid, username FROM customers WHERE customerid < 1000 AND username <'user100';ซึ่งเป็นแผนนี้:

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)

ความเข้าใจของฉันเกี่ยวกับโหนดนี้ :

ตามที่ได้อธิบายมีผู้อ่านบล็อกตารางตามลำดับดังนั้นจึงไม่ได้ผลิตค่าใช้จ่ายในการสุ่มตารางการเข้าถึงที่เกิดขึ้นเป็นเพียงการทำbitmap heap scanIndex Scan

หลังจากIndex Scanเสร็จสิ้นแล้ว PostgreSQL ไม่รู้วิธีดึงแถวอย่างเหมาะสมเพื่อหลีกเลี่ยงการไม่จำเป็นheap blocks reads(หรือhitsหากมีแคชร้อน) ดังนั้นจะคิดออกจะสร้างโครงสร้าง ( Bitmap Index Scan) เรียกว่าซึ่งในกรณีของฉันจะถูกสร้างขึ้นโดยการสร้างสองบิตแมปของดัชนีและการดำเนินการbitmap ตั้งแต่บิตแมปที่ได้รับการสร้างขึ้นได้ในขณะนี้สามารถอ่านตารางได้อย่างดีที่สุดตามลำดับหลีกเลี่ยงที่ไม่จำเป็นBITWISE ANDheap I/O-operations

นั่นคือสถานที่ที่มีคำถามมากมาย

คำถาม:เรามีเพียงบิตแมป PostgreSQL รู้ได้อย่างไรเพียงแค่บิตแมปเกี่ยวกับลำดับทางกายภาพของแถว หรือสร้างบิตแมปเพื่อให้องค์ประกอบใด ๆ ของมันสามารถแมปกับตัวชี้ไปยังหน้าได้อย่างง่ายดาย? ถ้าเป็นเช่นนั้นจะอธิบายทุกอย่าง แต่มันก็เป็นเพียงการคาดเดาของฉัน

ดังนั้นเราสามารถพูดได้ง่ายๆว่าการbitmap heap scan -> bitmap index scanสแกนตามลำดับ แต่เฉพาะส่วนที่เหมาะสมของตาราง?


ฉันเขียนคำอธิบายบางส่วนของที่นี่: stackoverflow.com/q/33100637/398670
Craig Ringer

@ CraigRinger ดูเหมือนว่าฉันจะไม่อธิบายอย่างถูกต้องในสิ่งที่ฉันไม่เข้าใจ แน่นอนตามที่คุณอธิบายเรามีบิตแมปที่ PostgreSQL อ่านตารางตามลำดับ ฉันไม่เข้าใจว่ามันจะเข้าใจบล็อกจริงที่กำหนดโดยบิตแมปที่เฉพาะเจาะจง001001010101011010101ได้อย่างไร หรือจริง ๆ แล้วมันไม่สำคัญและสิ่งที่เราต้องรู้ก็คือมันสามารถหาบล็อกด้วยบิตแมปในวิธีที่รวดเร็ว ...
St.Antario

อ๊ะคุณอาจเข้าใจผิดว่า "บิตแมป" หมายถึงที่นี่ ให้ฉันติดตามการแก้ไข
Craig Ringer

@CraigRinger บางทีผมเอา defintion จากที่นั่น
St.Antario

คำตอบ:


52

PostgreSQL รู้ได้อย่างไรเพียงแค่บิตแมปเกี่ยวกับลำดับทางกายภาพของแถว

บิตแมปเป็นหนึ่งบิตต่อหน้ากอง การสแกนดัชนีบิตแมปจะตั้งค่าบิตตามที่อยู่ของเพจฮีพที่รายการดัชนีชี้ไป

ดังนั้นเมื่อมันทำการสแกนบิตแมปฮีปมันก็แค่สแกนตารางเชิงเส้นอ่านบิตแมปเพื่อดูว่ามันควรจะรำคาญกับหน้าเฉพาะหรือค้นหามัน

หรือสร้างบิตแมปเพื่อให้องค์ประกอบใด ๆ ของมันสามารถแมปกับตัวชี้ไปยังหน้าได้อย่างง่ายดาย?

ไม่บิตแมปตรงกับ 1: 1 เพื่อกองหน้า

ผมเขียนบางมากขึ้นเกี่ยวกับเรื่องนี้ที่นี่


ดูเหมือนว่าคุณอาจเข้าใจผิดว่า "บิตแมป" หมายถึงอะไรในบริบทนี้

ไม่ใช่สตริงบิตเช่น "101011" ที่สร้างขึ้นสำหรับแต่ละหน้าฮีปหรือแต่ละดัชนีอ่านหรืออะไรก็ตาม

บิตแมปทั้งหมดเป็นอาร์เรย์บิตเดียวโดยมีบิตมากเท่าที่มีเพจฮีปในการสแกนความสัมพันธ์

หนึ่งบิตแมปถูกสร้างขึ้นโดยการสแกนดัชนีครั้งแรกเริ่มต้นด้วยรายการทั้งหมด 0 (เท็จ) เมื่อใดก็ตามที่พบรายการดัชนีที่ตรงกับเงื่อนไขการค้นหาที่อยู่ฮีปที่ชี้ไปตามรายการดัชนีนั้นจะถูกค้นหาเป็นออฟเซ็ตในบิตแมปและบิตนั้นจะถูกตั้งค่าเป็น 1 (จริง) ดังนั้นแทนที่จะค้นหาหน้าฮีปโดยตรงการสแกนดัชนีบิตแมปจะค้นหาตำแหน่งบิตที่สอดคล้องกันในบิตแมป

การสแกนดัชนีบิตแมปที่สองและเพิ่มเติมนั้นทำสิ่งเดียวกันกับดัชนีอื่นและเงื่อนไขการค้นหา

จากนั้นบิตแมปแต่ละอันจะถูกรวมเข้าด้วยกัน บิตแมปที่ได้จะมีหนึ่งบิตสำหรับแต่ละเพจฮีปโดยที่บิตนั้นเป็นจริงหากเป็นจริงในการสแกนดัชนีบิตแมปแต่ละรายการทั้งหมดนั่นคือเงื่อนไขการค้นหาที่ตรงกับการสแกนดัชนีทุกรายการ เหล่านี้เป็นหน้ากองเดียวที่เราต้องกังวลในการโหลดและตรวจสอบ เนื่องจากหน้าฮีปแต่ละหน้าอาจมีหลายแถวเราจึงต้องตรวจสอบแต่ละแถวเพื่อดูว่าตรงกับเงื่อนไขทั้งหมดหรือไม่นั่นคือส่วนที่ "ตรวจสอบเงื่อนไข" อีกครั้ง

สิ่งสำคัญอย่างหนึ่งที่ต้องเข้าใจทั้งหมดนี้คือที่อยู่ของ tuple ในรายการดัชนีชี้ไปที่แถวctidซึ่งเป็นการรวมกันของหมายเลขหน้าฮีปและออฟเซ็ตภายในเพจฮีป การสแกนดัชนีบิตแมปจะไม่สนใจออฟเซ็ตเนื่องจากมันจะตรวจสอบหน้าทั้งหมดแล้วและตั้งค่าบิตหากแถวใด ๆ ในหน้านั้นตรงกับเงื่อนไข


ตัวอย่างกราฟิก

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
+---------------------------------------------+

เมื่อบิตแมปถูกสร้างขึ้นในระดับบิตและดำเนินการกับพวกเขา:

+---------------------------------------------+
|100000000001000000010000000000000111100000000| bitmap 1
|000001000001000100010000000001000010000000010| bitmap 2
 &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
|000000000001000000010000000000000010000000000| Combined bitmap
+-----------+-------+--------------+----------+
            |       |              |
            v       v              v
Used to scan the heap only for matching pages:
+---------------------------------------------+
|___________X_______X______________X__________|
+---------------------------------------------+

การสแกน heap บิตแมปจะค้นหาจุดเริ่มต้นของแต่ละหน้าและอ่านหน้า:

+---------------------------------------------+
|___________X_______X______________X__________|
+---------------------------------------------+
seek------->^seek-->^seek--------->^
            |       |              |
            ------------------------
            only these pages read

และแต่ละหน้าอ่านจะถูกตรวจสอบอีกครั้งกับสภาพเนื่องจากอาจมี> 1 แถวต่อหน้าและไม่จำเป็นต้องตรงกับเงื่อนไขทั้งหมด


อาว่าเป็นสิ่งที่พวกเขาหมายโดยประชากรของบิตแมป
St.Antario

@ St.Antario ฉันได้เพิ่มกราฟิกเพื่ออธิบาย
Craig Ringer

ให้ฉันอธิบายอีกอย่างหนึ่งเกี่ยวกับบิตแมปสแกน คุณบอกว่าเรามีบิตแมปขนาด 1: 1 สำหรับหน้าฮีปและเราสามารถระบุเพจฮีปโดยดัชนีบิตในบิตแมป เนื่องจากความสัมพันธ์อาจมีหน้าบนดิสก์ในลำดับที่ไม่ต่อเนื่อง (ไม่ใช่แบบคลัสเตอร์) จึงค่อนข้างชัดเจนว่าเราสามารถระบุที่อยู่ของหน้าได้อย่างไรโดยเพียงแค่ชดเชยในบิตแมป ฉันเข้าใจ, วางแผนรู้วิธีการคำนวณที่อยู่หน้าโดยการชดเชยสำหรับความสัมพันธ์ที่ได้รับ มันเป็นเรื่องจริงเหรอ?
St.Antario

1
ดังนั้นเราต้องใส่หน้าทั้งหมดที่อยู่ในไดรฟ์ ยิ่งไปกว่านั้นข้อมูลของความสัมพันธ์อาจแพร่กระจายในไดรฟ์สองตัวขึ้นไป (ดังนั้นจึงเป็นการยากที่จะจินตนาการถึงลำดับเชิงเส้นของหน้าความสัมพันธ์ ) ดังนั้นการกำหนดออฟเซ็ตจริงของหน้าถัดไปจึงเป็นเรื่องยาก เพราะฉันเชื่อว่าด้วย "ออฟเซ็ต" คุณหมายถึงออฟเซ็ตทางกายภาพจริงที่สอดคล้องกับตำแหน่งทางกายภาพของไดรฟ์
St.Antario

2
PostgreSQL ไม่สนใจแม้แต่น้อยเกี่ยวกับไดรฟ์ มันสนใจเฉพาะไฟล์ต่าง ๆในระบบไฟล์เท่านั้น ตรรกะไฟล์สำหรับความสัมพันธ์เป็นเส้นตรงและต่อเนื่องกันและนั่นคือสิ่งที่บิตแมปที่มีมากกว่า (อาจมีไฟล์หลายไฟล์ แต่จะถือว่าเหมือนกับว่าต่อท้ายไฟล์และบิตแมปจะอยู่เหนือทุกไฟล์) คุณกำลังดูระดับนามธรรมที่ไม่ถูกต้อง (ในหมายเหตุด้านบิตแมปในการสแกนดัชนีบิตแมปไม่ได้คำนวณโดยผู้วางแผนซึ่งเป็นส่วนหนึ่งของวิธีการเข้าถึงดัชนี btree และเกี่ยวข้องกับผู้ดำเนินการมากกว่าผู้วางแผน)
Craig Ringer

3

โปรดอ้างอิงโพสต์บล็อกของฉัน https://rajeevrastogi.blogspot.in/2018/02/bitmap-scan-in-postgresql.html?showComment=1518410565792#c4647352762092142586 สำหรับรายละเอียดของการสแกนบิตแมปใน PostgreSQL

ภาพรวมฟังก์ชันการทำงานอย่างรวดเร็วโดยรวมของการสแกนบิตแมป:

  1. การสแกนบิตแมป Heap ขอ tuple จากการสแกนดัชนีบิตแมป

  2. การสแกนดัชนีบิตแมปจะสแกนดัชนีตามเงื่อนไขในลักษณะเดียวกับที่ทำในการสแกนดัชนีปกติ แต่แทนที่จะส่งคืน TID (ประกอบด้วยหน้าไม่มีและชดเชยภายในนั้น) ที่สอดคล้องกับข้อมูลฮีปจะเพิ่ม TID เหล่านั้นในบิตแมป เพื่อความเข้าใจอย่างง่ายคุณสามารถพิจารณาบิตแมปนี้ที่มีแฮชของทุกหน้า (แฮชตามหมายเลขหน้า) และแต่ละรายการหน้าจะมีอาเรย์ของออฟเซ็ตทั้งหมดภายในหน้านั้น

  3. จากนั้น Bitmap Heap Scan จะอ่านผ่านบิตแมปเพื่อรับข้อมูลฮีปที่สอดคล้องกับหมายเลขหน้าที่จัดเก็บและออฟเซ็ต จากนั้นจะตรวจสอบการมองเห็นคุณสมบัติ ฯลฯ และส่งกลับค่า tuple ตามผลลัพธ์ของการตรวจสอบทั้งหมดเหล่านี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.