กลับไปหน้าบทความ
#MySQL#Index#Query Performance#Database

เข้าใจ Index ใน MySQL ก่อนเพิ่มเพื่อแก้ Query ช้า

เรียนรู้การทำงานของ B-tree, composite index และลำดับคอลัมน์จาก WHERE, JOIN และ ORDER BY พร้อมข้อแลกเปลี่ยนด้านพื้นที่และความเร็วในการเขียนข้อมูล

16 กรกฎาคม 2569อ่านประมาณ 2 นาที

แชร์บทความ

เข้าใจ Index ใน MySQL ก่อนเพิ่มเพื่อแก้ Query ช้า

ภาพรวม

Index ใน MySQL คืออะไร คิดง่าย ๆ เหมือนสารบัญท้ายเล่มหนังสือครับ ถ้าไม่มีสารบัญ อยากหาคำว่า payment_status ก็ต้องเปิดอ่านทุกหน้า

ในตาราง MySQL ก็เหมือนกัน ถ้า query แบบนี้ SELECT * FROM orders WHERE user_id = 42; แล้ว orders มี 5 ล้านแถว แต่ไม่มี index ที่ user_id MySQL อาจต้องไล่ดูทีละแถว อันนี้เรียกว่า full table scan ช้าแบบเงียบ ๆ 🐢

Index ช่วยให้ MySQL กระโดดไปหาแถวที่น่าจะใช่ได้เร็วขึ้น เหมือนบอกว่า user_id 42 อยู่แถวประมาณนี้นะ ไม่ต้องอ่านทั้งตาราง

แต่ index ไม่ใช่เวทมนตร์ ใส่เยอะไปก็พังได้เหมือนกัน เพราะทุกครั้งที่ INSERT, UPDATE, DELETE MySQL ต้องอัปเดต index ด้วย ตารางที่เขียนหนัก ๆ index เยอะเกินไปจะทำให้ write ช้าลง

ปัญหาที่เจอบ่อยคือ มี index แล้ว แต่ query ยังช้า เช่น SELECT * FROM users WHERE LOWER(email) = 'a@b.com'; ถ้ามี index ที่ email MySQL อาจใช้ไม่ได้เต็มที่ เพราะเราเอา column ไปครอบด้วย function ทางแก้คือเก็บ email เป็น lowercase ตั้งแต่แรก แล้ว query ตรง ๆ WHERE email = 'a@b.com'

อีกเคสคือ wildcard นำหน้า WHERE name LIKE '%somchai%' index ปกติช่วยไม่ค่อยได้ เพราะไม่รู้จะเริ่มค้นจากตรงไหน แต่ถ้าเป็น WHERE name LIKE 'somchai%' ยังมีโอกาสใช้ index ได้ ถ้าต้องค้นข้อความจริงจัง ลองดู FULLTEXT index หรือ search engine แยก

Composite index ก็สำคัญมาก สมมติมี query หลักคือ SELECT * FROM orders WHERE user_id = 42 AND status = 'paid' ORDER BY created_at DESC; index ที่ดีอาจเป็น (user_id, status, created_at) เพราะกรอง user ก่อน กรอง status ต่อ แล้วเรียง created_at ได้ใกล้เคียงที่ต้องการ

แต่ลำดับ column มีผลนะครับ index (status, user_id) ไม่ได้เหมือน (user_id, status) ถ้า status มีแค่ paid, pending, cancel มันแยกข้อมูลได้น้อย เริ่มด้วย status อาจไม่ช่วยมาก ให้ดู column ที่กรองแล้วตัดข้อมูลได้เยอะก่อน เรียกว่า selectivity

วิธีเช็กอย่าเดา ใช้ EXPLAIN EXPLAIN SELECT * FROM orders WHERE user_id = 42; ดู key ว่าใช้ index ตัวไหน ดู type ถ้าเป็น ALL มักแปลว่า scan เยอะ ดู rows ว่าประเมินว่าจะอ่านกี่แถว ถ้า rows หลักล้าน แต่ผลลัพธ์จริงมีไม่กี่สิบ นี่คือกลิ่นว่าควรปรับ index หรือ query

อีกจุดที่ทำให้ช้าคือ SELECT * ถึงใช้ index หาเจอเร็ว แต่ถ้าต้องกลับไปอ่านข้อมูลทั้ง row จำนวนมาก ก็ยังหนักอยู่ ถ้าต้องการแค่ id, status, created_at ก็เลือกเท่าที่ใช้ บางทีทำ covering index ได้ เช่น index มี column ที่ query ต้องใช้ครบ MySQL ไม่ต้องกลับไปเปิด table เพิ่ม เร็วขึ้นแบบรู้สึกได้ ⚡

ข้อควรจำสั้น ๆ index column ที่ใช้ใน WHERE, JOIN, ORDER BY บ่อย ๆ อย่าสร้างตามความรู้สึก ดู slow query log ใช้ EXPLAIN วัดก่อนและหลังแก้

ถ้า query ช้า อย่าเริ่มด้วยการเพิ่ม server ให้ถามก่อนว่า MySQL กำลังอ่านกี่แถวเพื่อคืนกี่แถว ถ้าอ่านล้านแถวเพื่อคืน 20 แถว ปัญหาอาจไม่ใช่เครื่องไม่แรง แต่อาจเป็นสารบัญที่ยังไม่มี หรือมีแล้วแต่เปิดผิดหน้า 🙂

แนวทางนำไปใช้

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

สรุป

เรียนรู้การทำงานของ B-tree, composite index และลำดับคอลัมน์จาก WHERE, JOIN และ ORDER BY พร้อมข้อแลกเปลี่ยนด้านพื้นที่และความเร็วในการเขียนข้อมูล