ข้าม​ไป​ยัง​เนื้อหา

เงื่อนไข​บน placed_at ข้าม 19 จาก 20 กลุ่ม ส่วน total ที่​มี​ค่า​ไม่​ซ้ำ 125,327 ค่า ข้าม​ได้ 0 กลุ่ม

ห้า​บท​แรก​ถาม​ว่า​ค่า​หนึ่ง​ค่า​กิน​ที่​เท่าไร บท​นี้​เปลี่ยน​คำถาม มัน​ถาม​ว่า ค่า​ไหน​ที่​ไม่​ต้อง​อ่าน​เลย

คลัง column ตัด​แถว​ออก​เป็นก​ลุ่ม แล้ว​เก็บ min กับ max ของ​ทุก​กลุ่ม​ไว้ ถ้า​เงื่อนไข ของ​คำถาม​อยู่​นอก​ช่วง​นั้น ทั้ง​กลุ่ม​ถูก​ข้าม​ไป​โดย​ไม่​ต้อง​แตะ​สัก​หน้า

คำ​ทำนาย​ที่​สม​เหตุ​สม​ผล​คือ กลไก​นี้​ได้​ผล​ดี​บน column ที่​มี​ค่าที่​ไม่​ซ้ำ​น้อย เพราะ​ค่า​ซ้ำๆ น่า​จะ​ทำให้​ช่วง min ถึง max ของ​แต่ละ​กลุ่ม​แคบ​ลง

ค่าที่​วัด​ได้​ปฏิเสธ​คำ​ทำนาย​นั้น​ทั้ง​ข้อ status มี​ค่าที่​ไม่​ซ้ำ 7 ค่า และ​ข้าม​ได้ 0 กลุ่ม ส่วน id มี​ค่าที่​ไม่​ซ้ำ 200,000 ค่า และ​ข้าม​ได้ 19 กลุ่ม

พาด​หัว​ของ​บท​คือ total ซึ่ง​มี​ค่าที่​ไม่​ซ้ำ 125,327 ค่า ใช้ 14 บิต​ต่อ​ค่า เท่ากับ id เป๊ะ และ​ข้าม​ได้ 0 กลุ่ม

📦 ตัวเลข​ทุก​ตัว​ใน​บท​นี้​รัน​เอง​ได้ ไม่​ต้อง​มี Docker และ​ไม่​ต้อง​ต่อ​เน็ต

สั่ง python3 scripts/column-store/probe.py ได้​เลย มัน​ใช้ Python 3 กับ standard library ล้วน และ​ไม่มี container ให้​เก็บ​กวาด​ทีหลัง

ค่าที่​วัด​ได้​ทุก​ตัว​ที่​บท​นี้​พิมพ์​มี​คีย์​ของ​ตัว​เอง​อยู่​ใน scripts/column-store/expected/column-store.txt และ​ชื่อ​คีย์​นั้น​เขียน​กำกับ​ไว้​ใน​ทุก​ตาราง ตัวเลข​ใน​บท​นี้​จึง​อ้างอิง​เป็น​คู่​ของ​ทรง​กับ​คีย์​เสมอ

กลไก​อยู่​ที่ min กับ max ของ​ทุก​กลุ่ม ไม่ใช่​ที่​ค่า​ข้าง​ใน

หัวข้อ​ที่​มีชื่อ​ว่า “กลไก​อยู่​ที่ min กับ max ของ​ทุก​กลุ่ม ไม่ใช่​ที่​ค่า​ข้าง​ใน”

เขียน​สอง​ค่า​นั้น​ตอน​สร้าง​กลุ่ม แล้ว​ใช้​มัน​ตัด​กลุ่ม​ทิ้ง​ก่อน​เปิด​อ่าน

ตอน​เขียน​คลัง colstore.py เก็บ min กับ max ของ​ทุก row grouprow groupก้อน​ของ​แถว​ที่​คลัง​แนว column ตัด​ออก​มา​เป็น​หน่วย​เดียวกัน ทุก column ใน​ก้อน​เดียวกัน​ถือ​แถว​ชุด​เดียวกัน · ขอบเขต​ของ​ก้อน​เป็น​สิ่ง​ที่​ตัดสิน​ว่า dictionary ถูก​คัด​ลอก​ซ้ำ​กี่​ใบ และ zone map ข้าม​อะไร​ได้​บ้าง ไว้​ใน metadata ข้าง​เดียว​กับ offset และ​ความ​ยาว​ของ​กลุ่ม​นั้น

scripts/column-store/colstore.py:324 — สอง​ค่าที่​เขียน​ไว้​ตอน​สร้าง​กลุ่ม
vals = data[g * rg:(g + 1) * rg]
blob, m = encode_chunk(vals, kind, self.enc[col])
m["off"] = off
m["len"] = len(blob)
m["min"] = min(vals)
m["max"] = max(vals)
m["g"] = g

metadata ชุด​นี้​คือ zone mapzone mapค่า min และ max ของ​แต่ละ column chunk ที่​เก็บ​ไว้​ใน metadata เพื่อ​ให้​ข้าม​ทั้ง row group ได้​โดย​ไม่​ต้อง​อ่าน​ค่า​ข้าง​ใน · มัน​คือ​การ​ตัด​ทิ้ง ไม่ใช่​การ​ประมาณ คอร์ส​นี้​จึง​รายงาน​จำนวน​กลุ่ม​ที่​ข้าม​ได้​จริง​จาก​การ​รัน และ​ไม่​คำนวณ​ค่า​ประมาณ​ความ​เลือกสรร​สัก​ตัว และ​การ​ใช้​มัน​เป็นการ​เทียบ​สอง​บรรทัด​ต่อ​กลุ่ม ไม่ใช่​การ​เปิด​อ่าน​ค่า​ข้าง​ใน​กลุ่ม

scripts/column-store/colstore.py:355 — การ​ตัด​ทิ้ง ไม่ใช่​การ​ประมาณ
def prune(self, col, lo, hi):
"""คืนรายการ row group ที่ min/max ไม่ตัดออก · นี่คือการตัดทิ้ง ไม่ใช่การประมาณ"""
keep = []
for m in self.meta[col]:
if m["max"] < lo or m["min"] > hi:
continue
keep.append(m["g"])
return keep

การ​ส่ง​เงื่อนไข​ของ​คำถาม​ลง​ไป​ให้​ชั้น​ที่​เก็บ​ข้อมูล​ตัดสิน​ก่อน​อ่าน เรียก​ว่า predicate pushdownpredicate pushdownการ​ส่ง​เงื่อนไข​ลง​ไป​ให้​ชั้น​ที่​เก็บ​ข้อมูล​ตัดสิน​ก่อน​อ่าน · ค่า​ทั้งหมด​ข้าง​ล่าง​วัด​บน​คลัง column ทรง bit packing ที่​ตัด​เป็น 20 row group · เงื่อนไข​บน placed_at ใน​วัน​ที่ 90 ข้าม​ได้ 19 จาก 20 กลุ่ม สแกน 10,000 แถว ตรง 1,017 แถว และ​แตะ 29 หน้า · เงื่อนไข​บน customer ระหว่าง 995 ถึง 1004 ข้าม​ได้ 0 กลุ่ม สแกน 200,000 แถว ตรง 995 แถว และ​แตะ 384 หน้า · ส่วน heap ที่ heapfile.build_heap เขียน อ่าน​ทั้ง​ตาราง 3153 หน้า​ทั้ง​สอง​คำถาม และ prune คือ​ทั้งหมด​ที่​คลัง​ของ​คอร์ส​นี้​ทำ​ใน​ชั้น​นั้น

prune คืน​รายการ​กลุ่ม​ที่​รอด คำถาม​จึง​อ่าน​เฉพาะ​กลุ่ม​ใน​รายการ​นั้น และ​กลุ่ม​ที่​ถูก​ตัด​ออก ไม่​ถูก​เปิด​เลย​สัก​หน้า

scripts/column-store/probe.py:135 — คำถาม​หนึ่ง​ข้อ นับ​กลุ่ม​ที่​รอด​ก่อน แล้ว​ค่อย​อ่าน
def zone_query(store, col, lo, hi, extra=()):
"""ตัด row group ด้วย min/max แล้วอ่านเฉพาะกลุ่มที่เหลือ — นี่คือการตัดทิ้ง ไม่ใช่การประมาณ"""
keep = store.prune(col, lo, hi)
q = cs.Q(store)
matched = 0
scanned = 0
for g in keep:
vals = q.chunk(col, g)
scanned += len(vals)
for j, v in enumerate(vals):
if lo <= v <= hi:
matched += 1

ที่​นี่​ไม่มี​การ​ประมาณ​สัก​ขั้น ไม่มี​การ​เดา​ว่า​เงื่อนไข​จะ​ตรง​กี่​แถว มี​แต่​การ​เทียบ ช่วง​ของ​กลุ่ม​กับ​ช่วง​ของ​เงื่อนไข แล้ว​นับ​กลุ่ม​ที่​รอด​ออก​มา​เป็น​จำนวนเต็ม

คำถาม​สอง​ข้อ​ที่​เจอ​แถว​ใกล้​เคียง​กัน แต่​ข้าม​กลุ่ม​ได้​ต่าง​กัน​สุด​ขั้ว

หัวข้อ​ที่​มีชื่อ​ว่า “คำถาม​สอง​ข้อ​ที่​เจอ​แถว​ใกล้​เคียง​กัน แต่​ข้าม​กลุ่ม​ได้​ต่าง​กัน​สุด​ขั้ว”

เงื่อนไข​คนละ column บน​ตาราง​ใบ​เดียวกัน แล้ว​จำนวน​กลุ่ม​ที่​ข้าม​ได้​ห่าง​กัน​สุด​ช่วง

คำถาม​ข้อ​แรก​ถาม placed_at ใน​วัน​ที่ 90 ข้อ​ที่​สอง​ถาม customer ระหว่าง 995 ถึง 1004 ทั้ง​สอง​ข้อ​วิ่ง​บน​คลัง​ทรง bit packing ใบ​เดียวกัน ที่​ตัด​เป็น 20 กลุ่ม​เท่า​กัน

ทรง​ที่​วัด · ### 6_zone_mapplaced_at ในวันที่ 90customer ระหว่าง 995 ถึง 1004
กลุ่มทั้งหมด2020
กลุ่มที่เหลือ120
กลุ่มที่ข้าม190
แถวที่ตรง1,017995

แถว​สุดท้าย​คือ​แถว​ที่​ทำให้​การ​เทียบ​นี้​ยุติธรรม 1,017 กับ 995 อยู่​ระดับ​เดียวกัน สอง​คำถาม​จึง​ไม่​ได้​ต่าง​กัน​เพราะ​ข้อ​หนึ่ง​ถาม​แคบ​กว่า​อีก​ข้อ

ถ้า​จำนวน​แถว​ที่​ตรง​ของ​สอง​ข้อ​ห่าง​กัน​มาก ผล​ที่​ต่าง​กัน​จะ​อธิบาย​ด้วย​ความ​กว้าง​ของ​คำถาม​ได้​ทันที probe จึง​เลือก​ช่วง​ลูกค้า​ให้​จำนวน​แถว​มา​ลง​ใกล้​กับ​หนึ่ง​วัน​โดย​ตั้งใจ

ประโยค​ที่​บท​นี้​หัก​ล้าง

ประโยค​ที่​พบ​ทั่วไป​คือ zone map ได้​ผล​บน column ที่​มี​ค่าที่​ไม่​ซ้ำ​น้อย เพราะ​ช่วง​ของ แต่ละ​กลุ่ม​จะ​แคบ

status มี​ค่าที่​ไม่​ซ้ำ 7 ค่า ซึ่ง​น้อย​ที่สุด​ใน column ทั้ง​หก​ตัว และ​คีย์ กลุ่มที่ข้ามได้เมื่อถามค่าเดียวตรงกลาง ของ​มัน​เป็น 0

ค่าที่​ซ้ำ​มาก​ไม่​ได้​ทำให้​ช่วง​แคบ มัน​ทำให้​ทุก​กลุ่ม​มี​ค่า​ครบ​ทุก​แบบ ช่วง min ถึง max ของ​ทุก​กลุ่ม​จึง​ทับ​กัน​สนิท และ​ไม่มี​กลุ่ม​ไหน​ถูก​ตัด​ทิ้ง​ได้

ข้าม​ไม่​ได้​สัก​กลุ่ม ไม่​ได้​แปล​ว่า​แพง​ขึ้น​นิด​หน่อย มัน​แปล​ว่า​อ่าน​ทั้ง column

หัวข้อ​ที่​มีชื่อ​ว่า “ข้าม​ไม่​ได้​สัก​กลุ่ม ไม่​ได้​แปล​ว่า​แพง​ขึ้น​นิด​หน่อย มัน​แปล​ว่า​อ่าน​ทั้ง column”

เมื่อ​ไม่มี​กลุ่ม​ไหน​ถูก​ตัด จำนวน​แถว​ที่​สแกน​กลับ​ไป​เท่ากับ​ทั้ง​ตาราง

ทรง​ที่​วัด · ### 6_zone_mapplaced_at ในวันที่ 90customer ระหว่าง 995 ถึง 1004
แถวที่สแกน10,000200,000
หน้าที่แตะ_column เงื่อนไข15107
หน้าที่แตะ_รวม column ที่ดึงออกมา29384

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

สอง​แถว​ล่าง​เป็น​หน้าที่​แตะ แถว​กลาง​นับ​เฉพาะ column ที่​เงื่อนไข​อ่าน ส่วน​แถว​ล่าง​นับ ตอน​ดึง total ของ​แถว​ที่​ตรง​ออก​มา​ด้วย

ฝั่ง​คลัง​แนว​แถว​ไม่มี​กลไก​นี้​ให้​ใช้ heap ไม่​ได้​ถือ min กับ max ราย​กลุ่ม​ไว้​เลย มัน​จึง​ต้อง​อ่าน​ทั้ง​ตาราง​ทั้ง​สอง​คำถาม

ทรง​ที่​วัดคีย์​ใน​ผล​ของ probeหน้าที่​แตะ
heap ที่ heapfile.build_heap เขียน · ทั้ง​สอง​คำถามheap ต้องอ่านเท่าไรทั้งสองคำถาม3153

ค่า​เดียวกัน​ทั้ง​สอง​คำถาม​คือ​ประเด็น ฝั่ง heap ไม่มี​อะไร​ให้​ตัด​ทิ้ง ตัวเลข​ของ​มัน จึง​ไม่​ขยับ​ตาม​รูป​ของ column ที่​คำถาม​ถาม

ส่วน​ฝั่ง​คลัง column ตัวเลข​ขยับ​จาก 29 ไป​เป็น 384 ระหว่าง​สอง​คำถาม​ที่​เจอ​แถว ตรง​พอๆ กัน กลไก​นี้​จึง​ไม่ใช่​ของ​ที่​ได้​เปล่า มัน​ได้​ผล​กับ​บาง column เท่านั้น

หัวใจ​ของ​บท​คือ total ซึ่ง​มี​ค่าที่​ไม่​ซ้ำ​เป็น​แสน และ​ข้าม​ได้​ศูนย์​กลุ่ม

หัวข้อ​ที่​มีชื่อ​ว่า “หัวใจ​ของ​บท​คือ total ซึ่ง​มี​ค่าที่​ไม่​ซ้ำ​เป็น​แสน และ​ข้าม​ได้​ศูนย์​กลุ่ม”

จำนวน​ค่าที่​ไม่​ซ้ำ​และ​ความ​กว้าง​ของ​ตัว​รหัส​ไม่​ได้​ทำนาย​ผล​ของ​กลไก​นี้​เลย

probe ถาม ค่า​เดียว​ที่​อยู่​ตรง​กลาง ของ​แต่ละ column แล้ว​นับ​กลุ่ม​ที่​ตัด​ทิ้ง​ได้ บน​คลัง​ทรง bit packing ใบ​เดียวกัน​ที่​ตัด​เป็น 20 กลุ่ม

column · ### 10_ข้อที่ขัดกับตำราค่าที่ไม่ซ้ำบิตต่อค่าเมื่อ bit-packกลุ่มที่ข้ามได้เมื่อถามค่าเดียวตรงกลาง
id200,0001419
customer2,000110
status730
restaurant1040
placed_at196,8911419
total125,327140

อ่าน​สาม​แถว​ที่​ใช้ 14 บิต​ต่อ​ค่า​เท่า​กัน​เรียง​กัน id ข้าม​ได้ 19 placed_at ข้าม​ได้ 19 และ total ข้าม​ได้ 0

สาม column นี้​มี​ค่าที่​ไม่​ซ้ำ​อยู่​ใน​ระดับ​แสน​เหมือน​กัน และ​ตัว​รหัส​กว้าง​เท่า​กัน​เป๊ะ สอง​ตัว​นั้น​จึง​ทำนาย​ผล​ของ​กลไก​นี้​ไม่​ได้​เลย

ตัวแปร​ที่​เหลือ​อยู่​ตัว​เดียว​คือ ความ​สัมพันธ์​กับ​ลำดับ​ที่​เขียน​แถว​ลง​คลัง id เดิน ขึ้น​ตาม​ลำดับ​ที่​เขียน placed_at ก็​เดิน​ขึ้น​ตาม​ลำดับ​เดียวกัน ส่วน total ไม่​เดิน ตาม​อะไร​เลย

กลุ่ม​ที่ 0 ของ total จึง​ถือ​ค่า​ตั้งแต่​ต่ำ​สุด​ถึง​สูงสุด และ​กลุ่ม​ที่ 19 ก็​ถือ​ช่วง เดียวกัน ค่า​เดียว​ที่​ถาม​อยู่​ใน​ช่วง​ของ​ทุก​กลุ่ม และ​ไม่มี​กลุ่ม​ไหน​ถูก​ตัด​ทิ้ง

ลำดับ​ที่​เขียน เป็น​สิ่ง​เดียว​ที่​ตัดสิน​ว่า​กลุ่ม​ไหน​ถูก​ตัด​ทิ้ง​ได้

หัวข้อ​ที่​มีชื่อ​ว่า “ลำดับ​ที่​เขียน เป็น​สิ่ง​เดียว​ที่​ตัดสิน​ว่า​กลุ่ม​ไหน​ถูก​ตัด​ทิ้ง​ได้”

รูป​เดียว​ที่​วาง​สอง column ซึ่ง​มี​ค่าที่​ไม่​ซ้ำ​ระดับ​เดียวกัน​ไว้​คนละ​กิ่ง

flowchart TB
  W["ลำดับที่เขียนแถวลงคลัง · ตัดเป็น 20 กลุ่ม · กลุ่มละ 10,000 แถว"]
  W --> A["placed_at · เดินขึ้นตามลำดับที่เขียน · ช่วง min ถึง max ของแต่ละกลุ่มแทบไม่ทับกัน"]
  W --> B["total · ไม่เดินตามลำดับที่เขียน · ช่วง min ถึง max ของทุกกลุ่มทับกันสนิท"]
  A --> A1["เงื่อนไขวันที่ 90 · ข้าม 19 กลุ่ม · สแกน 10,000 แถว"]
  B --> B1["เงื่อนไขค่าเดียวตรงกลาง · ข้าม 0 กลุ่ม"]
  A1 --> N["ค่าที่ไม่ซ้ำของสอง column นี้อยู่ระดับแสนทั้งคู่ · ตัวรหัสกว้าง 14 บิตเท่ากัน"]
  B1 --> N

คำ​บรรยาย​ภาพ: สอง​กิ่ง​เริ่ม​จาก​ลำดับ​ที่​เขียน​ชุด​เดียวกัน และ​จบ​ที่​ผล​ตรง​ข้าม​กัน กล่อง​ล่าง​สุด​คือ​สอง​ค่าที่​เท่า​กัน​ทั้ง​คู่ จึง​ไม่ใช่​สิ่ง​ที่​ทำให้​ผล​ต่าง​กัน

ตัวเลข​มา​จาก​การ​รัน ส่วน​เหตุผล​ที่ min กับ max อยู่​ใน metadata มา​จาก​รูป​แบบ

ค่า 19 และ 0 กับ​หน้าที่​แตะ 29 และ 384 เป็น​สิ่ง​ที่ probe วัด​จาก​คลัง ที่ colstore.py เขียน​ลง​จริง ส่วน 3153 วัด​จาก heap ที่ heapfile.build_heap ของ​คอร์ส​ที่ 26 เขียน

ทั้ง​สอง​ฝั่ง​นับ​หน้า​ด้วย Pager.reads ตัว​เดียวกัน ตัวเลข​สอง​ฝั่ง​จึง​วาง​ทาบ​กัน​ได้

ส่วน​เหตุผล​ที่​รูป​แบบ​แนว column เก็บ​สถิติ min กับ max ไว้​ระดับ column chunk ใน metadata ท้าย​คลัง เป็น​สิ่ง​ที่​เอกสาร​ของ Parquet กำหนด​ไว้ บท​นี้​ไม่​ได้​พิสูจน์​ข้อ​นั้น

คลัง​ของ​คอร์ส​นี้​ไม่ใช่ Parquet มัน​ยืม​กลไก​มา​ใช้ แล้ว​วัดผล​บน​ตาราง​ใบ​เดียว​ของ​ตัว​เอง ผล​ที่​ได้​จึง​เป็น​ผล​ของ​ตาราง​ใบ​นี้ ไม่ใช่​ค่าที่​รูป​แบบ​รับ​ประกัน

สิ่ง​ที่​บท​นี้​ไม่​ได้​ทำ และ​ไม่​ควร​มี​ใคร​เติม​ให้

บท​นี้​ไม่​รายงาน​ค่า​ประมาณ​ความ​เลือกสรร​สัก​ตัว zone map คือ​การ​ตัด​ทิ้ง ไม่ใช่​การ​ประมาณ prune เทียบ​ช่วง​แล้ว​คืน​รายการ​กลุ่ม มัน​ไม่​ได้​เดา​ว่า​จะ​ตรง​กี่​แถว

การ​ประมาณ​จำนวน​แถว​ด้วย histogram และ​ข้อ​สมมติ​เรื่อง​การก​ระ​จา​ย​ตัว เป็น​เรื่อง​ของ คอร์ส​ที่ 26 ซึ่ง​มี​คำ​และ​ตัวเลข​ของ​ตัว​เอง​อยู่​แล้ว

ค่า 1,017 กับ 995 ใน​บท​นี้​เป็น จำนวน​แถว​ที่​นับ​ได้​จริง ไม่ใช่​ค่า​ประมาณ และ​มัน​มี​ไว้​พิสูจน์​ว่า​สอง​คำถาม​อยู่​ระดับ​เดียวกัน

ถ้า​ลำดับ​ที่​เขียน​เป็น​ตัวแปร แล้ว​เปลี่ยน​ลำดับ​นั้น​จะ​เกิด​อะไร​ขึ้น

ตาราง​ใน​บท​นี้​เรียง​ตาม placed_at มา​ตั้งแต่​ต้น zone map ของ column ตัว​นั้น​จึง​ทำงาน และ​ของ customer กับ total ไม่​ทำงาน

คำถาม​ถัด​ไป​ที่​ตาม​มา​เอง​คือ ถ้า​เรียง​ใหม่​ตาม column ที่​ถาม​บ่อย​กว่า จะ​ได้​ผล​นั้น​คืน​มา​ไหม

บท​ที่ 7 เรียง​ตาม restaurant แล้ว​วัด​ทั้ง​สอง​ฝั่ง ทั้ง​ฝั่ง​ที่​ตื่น​ขึ้น​และ​ฝั่ง​ที่ ทรุด​ลง เพราะ​ตาราง​มี​ลำดับ​ได้​ลำดับ​เดียว การ​เลือก​ลำดับ​จึง​เป็นการ​ยก​ส่วน​ได้​เปรียบ จาก column หนึ่ง​ไป​ให้​อีก column

อ่าน​ต่อ​ที่ บท​ที่ 7 · เรียง​เพื่อ column หนึ่ง คือ​จ่าย​ให้​อีก column


🔗 อ้างอิง​ต้นทาง​ของ​บท​นี้
  • Apache Parquet — Metadata (เข้า​ถึง 2026-09-10) — ที่มา​ของ​กลไก​ที่​ว่า​รูป​แบบ​เก็บ​สถิติ​ของ column chunk ไว้​ใน metadata เพื่อ​ให้​ตัว​อ่าน​ตัด​ส่วน​ที่​เงื่อนไข​เอื้อม​ไม่​ถึง​ทิ้ง​ได้ · เป็น​ข้อ​อ้าง​เรื่อง​รูป​แบบ ไม่ใช่​ผล​การ​วัด​ของ​คอร์ส​นี้

  • Apache Parquet — File Format (เข้า​ถึง 2026-09-10) — ที่มา​ของ​ข้อ​ที่​ว่า metadata ถูก​เขียน​ไว้​หลัง​ข้อมูล ซึ่ง​เป็น​เหตุผล ที่​ตัว​อ่าน​หยิบ​สถิติ​ทั้ง​คลัง​ได้​ก่อน​แตะ​ข้อมูล​จริง

  • ตัวเลข​ทุก​ตัว​ใน​บท​นี้​มา​จาก python3 scripts/column-store/probe.py · ค่าที่​ตรึง​ไว้​อยู่​ที่ scripts/column-store/expected/column-store.txt หมวด ### 6_zone_map และ​หมวด ### 10_ข้อที่ขัดกับตำรา

  • fence สาม block ข้าง​บน​ยก​มา​จาก scripts/column-store/colstore.py บรรทัด​ที่ 324 และ 355 กับ scripts/column-store/probe.py บรรทัด​ที่ 135 · คอร์ส​นี้​ไม่​แก้​อะไร​ใน scripts/query-engine/qe/ แม้แต่ byte เดียว

เช็กความเข้าใจ — บทที่ 6

ข้อ 1 / 3

เงื่อนไขบน placed_at ในวันที่ 90 กับเงื่อนไขบน customer ระหว่าง 995 ถึง 1004 ให้ผลต่างกันอย่างไร และอะไรทำให้การเทียบนี้ยุติธรรม