ทดสอบว่า MySQL เพิ่มประสิทธิภาพ (eliminate) common subexpressions ระหว่าง SELECT และ GROUP BY/HAVING หรือไม่ โดยใช้ SLEEP() วัดเวลา
สร้างตารางตัวอย่าง
mysql> CREATE TABLE sleepDemo (value INT); mysql> INSERT INTO sleepDemo VALUES (40), (60), (60);
แสดงข้อมูล
mysql> SELECT * FROM sleepDemo;
+-------+ | value | +-------+ | 40 | | 60 | | 60 | +-------+
กรณีที่ 1: ซ้ำ expression ใน SELECT และ GROUP BY
mysql> SELECT value + SLEEP(3)
-> FROM sleepDemo
-> GROUP BY value + SLEEP(3);
ผลลัพธ์ (ใช้เวลา 9 วินาที = 3 แถว × 3 วินาที):
+----------------+ | value+SLEEP(3) | +----------------+ | 40 | | 60 | +----------------+ 2 rows in set (9.00 sec)
สรุป: MySQL ไม่กำจัด common subexpression - คำนวณ SLEEP(3) ทุกครั้งที่เจอ
กรณีที่ 2: ใช้ ALIAS ใน GROUP BY
mysql> SELECT value + SLEEP(3) AS v
-> FROM sleepDemo
-> GROUP BY v;
ผลลัพธ์ (ใช้เวลา 9 วินาที = 3 แถว × 3 วินาที):
+------+ | v | +------+ | 40 | | 60 | +------+ 2 rows in set (9.00 sec)
สรุป: ยังคงคำนวณซ้ำ แม้ใช้ ALIAS
การทดสอบเพิ่มเติม: ใช้ Subquery/Derived Table
-- คำนวณครั้งเดียวใน subquery แล้วค่อย GROUP BY
SELECT v FROM (
SELECT value + SLEEP(3) AS v FROM sleepDemo
) AS t
GROUP BY v;
ผลลัพธ์: ใช้เวลา 9 วินาที (ยังคงคำนวณ 3 ครั้ง เพราะ subquery ยังประมวลผลทุกแถว)
วิธีแก้: คำนวณครั้งเดียวด้วย CTE (MySQL 8.0+)
WITH computed AS (
SELECT value, value + SLEEP(3) AS v FROM sleepDemo
)
SELECT v FROM computed GROUP BY v;
ยังคง 9 วินาที เพราะ CTE ยังต้องคำนวณทุกแถว
วิธีแก้จริง: ลดจำนวนแถวก่อนคำนวณ
-- DISTINCT ก่อน คำนวณทีหลัง
WITH distinct_vals AS (
SELECT DISTINCT value FROM sleepDemo
)
SELECT value + SLEEP(3) AS v FROM distinct_vals;
ผลลัพธ์: ใช้เวลา 6 วินาที (2 ค่าที่ไม่ซ้ำ × 3 วินาที) ✓
สรุป
- MySQL ไม่ได้ eliminate common subexpressions อัตโนมัติ
- Expression ใน SELECT และ GROUP BY/HAVING จะคำนวณแยกกัน
- ใช้
DISTINCTหรือ Subquery กรองค่าก่อน ค่อยคำนวณ expression ที่แพง - หลีกเลี่ยงฟังก์ชันที่แพง (SLEEP, UUID, complex UDF) ใน SELECT/GROUP BY โดยตรง