# แค่ 20 บรรทัด แต่กวาดไปหนึ่งล้านบรรทัด? คู่มือการปรับแต่งประสิทธิภาพ SQL ฉบับสมบูรณ์
## หนึ่ง, หัวข้อ
แค่ 20 บรรทัด แต่กวาดไปหนึ่งล้านบรรทัด? คู่มือการปรับแต่งประสิทธิภาพ SQL ฉบับสมบูรณ์
ทางเลือก:
- ส่งคืน 20 บรรทัด สแกนหนึ่งล้านบรรทัด: อธิบายการปรับแต่ง SQL ให้เข้าใจในครั้งเดียว
- มีดัชนีแต่ไม่ยอมใช้? อ่าน EXPLAIN ให้เข้าใจก่อนลงมือแก้
- ทำไม Deep Paging อย่าง LIMIT หนึ่งล้าน ถึงยิ่งเปิดยิ่งช้า
- เครื่องไม่ได้พัง ดัชนีก็ยังอยู่ ที่ช้าเพราะ SQL คำสั่งนี้ทำงานสูญเปล่ามากเกินไป
## สอง, บทนำ
รายการคำสั่งปกติใช้เวลาแปดสิบมิลลิวินาที ผู้ใช้เลื่อนไปหน้าลึกๆ กลับต้องรอนานกว่าสองวินาที
ตัวเลขสองตัวในบันทึกการค้นหาช้าไม่ตรงกัน: Rows_sent คือ 20, Rows_examined คือ 1000020—
เพื่อให้ได้ 20 บรรทัดนี้ ฐานข้อมูลต้องอ่านหนึ่งล้านบรรทัดแรกขึ้นมาทีละบรรทัดแล้วทิ้งไป
เครื่องไม่ได้พัง ดัชนีก็ยังอยู่ ที่ช้าเพราะ SQL คำสั่งนี้ทำให้ฐานข้อมูลทำงานสูญเปล่ามากเกินไป
พูดให้ถึงที่สุดแล้ว การปรับแต่ง SQL มีเรื่องเดียว: ทำให้ฐานข้อมูลอ่านน้อยลง เดินทางน้อยลง
วิดีโอนี้ทำตามลำดับการตรวจสอบ: หา SQL ช้าก่อน, ใช้ EXPLAIN ดูแผนการทำงาน,
จากนั้นแยกแยะประเภทความช้าทั่วไป เช่น ดัชนี, การแบ่งหน้า, การจัดเรียง, การเชื่อมโยง และระดับแอปพลิเคชัน พร้อมวิธีแก้ในแต่ละประเภท
✅ คุณจะเข้าใจ:
· บันทึกการค้นหาช้า + pt-query-digest: สิ่งที่ประหยัดเวลาในการปรับแต่งมากที่สุด มักจะเป็นตัวที่ "ครั้งละสองร้อยมิลลิวินาที วันละหนึ่งล้านครั้ง"
· เวลาของการค้นหาครั้งหนึ่งหมดไปกับอะไร: เพจ (page), buffer pool, การอ่านแบบต่อเนื่อง vs การอ่านแบบสุ่ม
· อ่าน EXPLAIN ให้เข้าใจ: type / key / rows / Extra และดูเวลาจริงด้วย EXPLAIN ANALYZE
· B+ Tree, Table Lookup (การกลับไปดึงข้อมูลที่ตาราง) และ Covering Index (ดัชนีครอบคลุม): อย่าเขียน SELECT * ตามใจชอบ
· ดัชนีร่วม (Composite Index): Prefix ทางซ้ายสุด, การตัดช่วง; ค่าเท่ากันอยู่หน้า ช่วงอยู่หลัง
· 4 รูปแบบที่ทำให้ดัชนีใช้ไม่ได้: ใช้ฟังก์ชันครอบคอลัมน์, แปลงชนิดข้อมูลโดยปริยาย, ค้นหาแบบ Left Fuzzy (ซ้ายหลวม), OR
· สวนทางกับสามัญสำนึก: มีดัชนีแต่ตัวเพิ่มประสิทธิภาพกลับเลือก Full Table Scan (สแกนตารางเต็ม)—เมื่อมีการดึงข้อมูลกลับ (Lookup) มากเกินไป การอ่านแบบสุ่มจะมีราคาแพงกว่าการสแกนแบบต่อเนื่อง
· Deep Paging: เคอร์เซอร์เพจจิ้ง (Cursor Paging) และ Deferred Join (การเชื่อมโยงแบบล่าช้า), เลิกใช้ LIMIT หนึ่งล้านซะที
· filesort / ตารางชั่วคราว: จัดลำดับการเรียงและจัดกลุ่มให้ตรงกับลำดับดัชนี
· JOIN และ COUNT: คอลัมน์ที่เชื่อมต้องมีดัชนี; COUNT(*) ของ InnoDB นับสดทีละรายการ
· 3 หลุมพรางระดับแอปพลิเคชัน: N+1, การแทรกทีละรายการ, ธุรกรรมยาว (Long Transaction)
⏱ ไทม์ไลน์บท (คลิกเพื่อข้าม)
00:00 อินโทร: แค่ 20 บรรทัด แต่กวาดไปหนึ่งล้านบรรทัด
01:09 ค้นหา SQL ช้าออกมาก่อน
02:29 แทรก: Duoke360
03:15 การค้นหาหนึ่งครั้ง เวลาหมดไปกับอะไร
04:30 ทำความเข้าใจ EXPLAIN
05:51 B+ Tree, Table Lookup และ Covering Index
07:05 ดัชนีร่วม: Prefix ทางซ้ายสุดและการตัดช่วง
08:17 4 รูปแบบที่ทำให้ดัชนีใช้ไม่ได้
09:37 สวนทางสามัญสำนึก: มีดัชนีแต่ไม่ยอมใช้
10:53 Deep Paging: LIMIT หนึ่งล้าน
12:12 การเรียงลำดับและการจัดกลุ่ม: filesort และตารางชั่วคราว
13:37 JOIN และ COUNT
15:06 3 หลุมพรางระดับแอปพลิเคชัน
16:29 รายการตรวจสอบและสรุป
ความยาววิดีโอประมาณ 17:44 Duoke360: https://duoke360.com/
เหมาะสำหรับ: นักพัฒนาสาย Backend ที่เคยเขียน SQL และเคยโดน SQL ช้าบนระบบจริงเล่นงาน รวมถึงผู้ที่กำลังจะสัมภาษณ์ในหัวข้อดัชนี, EXPLAIN และ Deep Paging
ไม่ต้องอ่านซอร์สโค้ด MySQL มาก่อน ขอแค่ดูบันทึกแบบช้า (Slow Log) เป็นก็ติดตามได้
สรุปสั้นๆ ในประโยคเดียว: ทำให้ฐานข้อมูลอ่านน้อยลง เดินทางน้อยลง;
ทุกๆ การเปลี่ยนแปลงใช้ตัวเลขจาก EXPLAIN เป็นเครื่องยืนยัน
รู้สึกว่ามีประโยชน์ ฝากกดไลค์ กดแชร์ กดติดตามด้วยนะ~ มีคำถามพูดคุยกันได้ที่ช่องคอมเมนต์
## สาม, แท็ก Tag
#การปรับแต่งSQL #MySQL #ค้นหาช้า #EXPLAIN #ดัชนี #B+Tree #DeepPaging #CoveringIndex #ดัชนีร่วม #filesort #พัฒนาเบื้องหลัง #ฐานข้อมูล #สัมภาษณ์ #คู่มือเขียนโปรแกรม #InnoDB #pt-query-digest
---
## สี่, คำสำคัญ
การปรับแต่ง SQL, ประสิทธิภาพ MySQL, ค้นหาช้า, slow_query_log, pt-query-digest,
EXPLAIN, EXPLAIN ANALYZE, type ALL, Using filesort, Using temporary,
B+ Tree, คลัสเตอร์อินเด็กซ์, Table Lookup, Covering Index, Using index,
ดัชนีร่วม, Prefix ทางซ้ายสุด, การตัดช่วง, Index Condition Pushdown,
ดัชนีใช้งานไม่ได้, แปลงชนิดข้อมูลโดยปริยาย, ค้นหาแบบ Left Fuzzy LIKE, FORCE INDEX, ANALYZE TABLE,
Deep Paging, LIMIT OFFSET, เคอร์เซอร์เพจจิ้ง, Deferred Join,
filesort, sort_buffer, ตารางชั่วคราว, GROUP BY,
JOIN, Nested Loop, Hash Join, COUNT(*), N+1, ธุรกรรมยาว, InnoDB buffer pool