0Pricing
SQL Interview Prep · บทเรียน

การสแกนตามลำดับเทียบกับการสแกนดัชนีและการสแกนเฉพาะดัชนี

เหตุผลที่ตัววางแผนเลือกแต่ละแบบ และสิ่งที่ตัวเลือกนั้นบอกเกี่ยวกับคำสั่งค้นหาของคุณ

การสแกนตามลำดับเทียบกับการสแกนดัชนีและการสแกนเฉพาะดัชนี เป็นบทเรียน SQL Interview Prep ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน SQL Interview Prep และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส SQL Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน

สามวิธีในการอ่านตาราง

เมื่อตัววางแผนต้องการแถวจากตาราง ตัววางแผนจะเลือกวิธีการเข้าถึงหนึ่งในสามวิธี และผู้สัมภาษณ์คาดหวังให้คุณบอกได้ครบทั้งสามวิธี:

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

การรู้ว่าเหตุใดตัววางแผนจึงเลือกแต่ละวิธีคือหัวใจของบทเรียนนี้ และเป็นคำถามระดับผู้มีประสบการณ์สูงที่มักถูกถามอย่างแน่นอน

การสแกนตามลำดับทำอะไร

การสแกนตามลำดับจะอ่านหน้าของตารางทีละหน้าต่อกัน และใช้ตัวกรองกับแต่ละแถว ไม่มีการใช้ดัชนี

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

ตัวอย่างคือ สแกน orders แล้วเก็บแถวที่ amount > 100 หากคำสั่งซื้อส่วนใหญ่มีจำนวนเงินเกิน 100 การสแกนตามลำดับก็ถูกต้อง

EXPLAIN SELECT * FROM orders WHERE amount > 100;

Seq Scan on orders  (cost=0.00..18334.00 rows=900000 width=64)
  Filter: (amount > 100)

การสแกนดัชนีทำอะไร

การสแกนดัชนีใช้ต้นไม้ B เพื่อกระโดดตรงไปยังคีย์ที่ตรงกัน แล้วอ่านแถวที่เกี่ยวข้องจากฮีปของตาราง

วิธีนี้โดดเด่นเมื่อ ตัวกรองมีความจำเพาะสูงและส่งคืนแถวเพียงส่วนน้อยของตาราง การค้นหา 5 แถวผ่านดัชนีย่อมดีกว่าการอ่าน 10 ล้านแถว

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

EXPLAIN SELECT * FROM orders WHERE customer_id = 42;

Index Scan using idx_orders_customer on orders
  (cost=0.42..38.50 rows=12 width=64)
  Index Cond: (customer_id = 42)

ความจำเพาะในการเลือกเป็นตัวตัดสิน

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

  • ความจำเพาะสูง (มีแถวตรงกันน้อย เช่น รหัสเฉพาะ) เหมาะกับการสแกนดัชนี
  • ความจำเพาะต่ำ (มีแถวตรงกันมาก เช่น status IS NOT NULL) เหมาะกับการสแกนตามลำดับ

กฎโดยคร่าว ๆ คือ เมื่อคำสั่งสอบถามส่งคืนแถวม​​ากกว่าประมาณ 5 ถึง 10 เปอร์เซ็นต์ของตาราง ตัววางแผนมักเลือกการสแกนตามลำดับ เพราะการดึงข้อมูลจากฮีปแบบสุ่มของดัชนีมีค่าใช้จ่ายสูงกว่าการอ่านทุกอย่างตามลำดับ

การสแกนเฉพาะดัชนี

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

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

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

EXPLAIN SELECT customer_id FROM orders WHERE customer_id = 42;

Index Only Scan using idx_orders_customer on orders
  (cost=0.42..8.44 rows=12 width=4)
  Index Cond: (customer_id = 42)

ข้อจำกัดของแผนผังการมองเห็น

ผู้สัมภาษณ์ชอบรายละเอียดนี้มาก การสแกนเฉพาะดัชนียังคงต้องยืนยันว่าแต่ละแถวมองเห็นได้สำหรับธุรกรรมของคุณ (MVCC) และดัชนีเพียงอย่างเดียวไม่ได้เก็บข้อมูลการมองเห็นไว้

Postgres ใช้แผนผังการมองเห็น: หากหน้าหนึ่งถูกทำเครื่องหมายว่ามองเห็นทั้งหมด ระบบจะข้ามฮีป แต่หากไม่ใช่ ระบบก็ต้องดึงแถวจากฮีปอยู่ดี แผนจะแสดง Heap Fetches: N

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

Index Only Scan using idx_orders_customer on orders
  (actual time=0.01..0.03 rows=12 loops=1)
  Heap Fetches: 0

การสแกนแบบบิตแมป: ทางสายกลาง

มีวิธีที่สี่ซึ่งมักปรากฏในแผน นั่นคือการสแกนฮีปแบบบิตแมป ตัววางแผนเลือกวิธีนี้เมื่อเพรดิเคตตรงกับแถวมากกว่าจำนวนที่การสแกนดัชนีแบบปกติต้องการ แต่น้อยกว่าจำนวนที่ต้องอ่านทั้งตาราง

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

Bitmap Heap Scan on orders  (cost=12.0..520.0 rows=8000)
  Recheck Cond: (status = 'pending')
  ->  Bitmap Index Scan on idx_orders_status
        (cost=0..12 rows=8000)
        Index Cond: (status = 'pending')

เหตุผลที่ตัววางแผนไม่ใช้ดัชนีของคุณ

คำถามสัมภาษณ์ที่พบบ่อยคือ: ฉันเพิ่มดัชนีแล้ว แต่แผนยังคงทำการสแกนตามลำดับ ทำไม? เหตุผลที่พบบ่อยมีดังนี้:

  • เพรดิเคตมีความจำเพาะไม่สูง การสแกนจึงมีค่าใช้จ่ายถูกกว่าอย่างแท้จริง
  • ฟังก์ชันครอบคอลัมน์: WHERE lower(email) = ... ไม่สามารถใช้ดัชนีทั่วไปบน email ได้
  • ชนิดข้อมูลไม่ตรงกัน ทำให้เกิดการแปลงชนิดข้อมูลโดยนัย ซึ่งขัดขวางการใช้ดัชนี
  • สถิติไม่เป็นปัจจุบัน ให้เรียกใช้ ANALYZE
  • ตารางมีขนาดเล็กมาก การสแกนไม่กี่หน้ามีค่าใช้จ่ายถูกว่าค่าใช้จ่ายส่วนเกินของดัชนี

ตัวอย่างการวินิจฉัย

สมมติว่า orders มีดัชนีบน created_at แต่คำสั่งสอบถามนี้ยังคงสแกนตามลำดับ:

สาเหตุคือ DATE(created_at) การครอบคอลัมน์ด้วยฟังก์ชันทำให้ไม่สามารถใช้ดัชนีบนคอลัมน์เดิมได้ วิธีแก้คือเขียนใหม่เป็นเพรดิเคตแบบช่วงที่ปล่อยคอลัมน์ไว้โดยไม่มีฟังก์ชันครอบ หรือสร้างดัชนีนิพจน์บน DATE(created_at)

-- Slow: function on the indexed column
WHERE DATE(created_at) = '2026-01-01'

-- Fast: bare column, range uses the index
WHERE created_at >= '2026-01-01'
  AND created_at <  '2026-01-02'

การเปรียบเทียบวิธีการ

จำการเปรียบเทียบนี้ไว้สำหรับการสัมภาษณ์:

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

ตัววางแผนเลือกวิธีโดยพิจารณาต้นทุนที่ประมาณการไว้ ซึ่งขับเคลื่อนหลัก ๆ ด้วยความจำเพาะในการเลือกและสถิติ

บังคับการทดสอบ (และเหตุผลที่ไม่ควรใช้ในระบบจริง)

เพื่อพิสูจน์ประเด็นหนึ่งในการพัฒนา คุณสามารถชักนำตัววางแผนชั่วคราวได้: SET enable_seqscan = off; จะบังคับให้ตัววางแผนเลือกดัชนีเป็นหลัก เพื่อให้คุณเปรียบเทียบแผนได้

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

SET enable_seqscan = off;
EXPLAIN ANALYZE SELECT * FROM orders WHERE amount > 100;
SET enable_seqscan = on;

ตรวจสอบอย่างรวดเร็ว

คำสั่งสอบถามเลือกเฉพาะ email และกรองด้วย email โดยมีดัชนีต้นไม้ B บน email แผนแสดง Index Only Scan เหตุใดวิธีนี้จึงเร็วกว่าการสแกนดัชนีทั่วไป?

ทบทวน

ประเด็นสำคัญเกี่ยวกับวิธีการเข้าถึง:

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

คำถามที่พบบ่อย

บทเรียน “การสแกนตามลำดับเทียบกับการสแกนดัชนีและการสแกนเฉพาะดัชนี” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การสแกนตามลำดับเทียบกับการสแกนดัชนีและการสแกนเฉพาะดัชนี” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส SQL Interview Prep ให้อัปเกรดเป็น CoddyKit PRO คอร์ส SQL Interview Prep มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การสแกนตามลำดับเทียบกับการสแกนดัชนีและการสแกนเฉพาะดัชนี”

เหตุผลที่ตัววางแผนเลือกแต่ละแบบ และสิ่งที่ตัวเลือกนั้นบอกเกี่ยวกับคำสั่งค้นหาของคุณ คุณปฏิบัติ SQL Interview Prep ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน SQL Interview Prep หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน SQL Interview Prep บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “การสแกนตามลำดับเทียบกับการสแกนดัชนีและการสแกนเฉพาะดัชนี” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน SQL Interview Prep นี้ได้ไหม

ได้ บทเรียน SQL Interview Prep ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. อ่านแผน EXPLAIN
  2. การสแกนตามลำดับเทียบกับการสแกนดัชนีและการสแกนเฉพาะดัชนี
  3. อัลกอริทึมการเชื่อมตาราง: ลูปซ้อน แฮช และผสาน
  4. ค้นหาและแก้ไขคำสั่งค้นหาที่ช้า
← กลับไปที่ SQL Interview Prep