คำสั่ง COUNT(DISTINCT column) อาจช้าเมื่อข้อมูลเยอะ เพราะต้องสแกนและจัดกลุ่มค่าที่ไม่ซ้ำทั้งหมด วิธีเร่งความเร็วคือสร้าง INDEX บนคอลัมน์ที่ใช้ใน DISTINCT
ตัวอย่างการใช้งาน
1. สร้างตารางพร้อม INDEX แบบ Composite
mysql> create table DemoTable1905 (
-> FirstName varchar(20),
-> LastName varchar(20),
-> INDEX F_L_Name(FirstName, LastName)
-> ); Query OK, 0 rows affected (0.00 sec)
2. เพิ่มข้อมูลทดสอบ
mysql> insert into DemoTable1905 values('John','Smith'); Query OK, 1 row affected (0.00 sec)
mysql> insert into DemoTable1905 values('John','Doe'); Query OK, 1 row affected (0.00 sec)
mysql> insert into DemoTable1905 values('Adam','Smith'); Query OK, 1 row affected (0.00 sec)
mysql> insert into DemoTable1905 values('John','Doe'); Query OK, 1 row affected (0.00 sec)
mysql> insert into DemoTable1905 values('Chris','Brown'); Query OK, 1 row affected (0.00 sec)
mysql> insert into DemoTable1905 values('Adam','Smith'); Query OK, 1 row affected (0.00 sec)
ข้อมูลทั้งหมด:
mysql> select * from DemoTable1905;
+-----------+----------+ | FirstName | LastName | +-----------+----------+ | Adam | Smith | | Adam | Smith | | Chris | Brown | | John | Doe | | John | Doe | | John | Smith | +-----------+----------+ 6 rows in set (0.00 sec)
3. นับค่า FirstName ที่ไม่ซ้ำ
mysql> select count(distinct FirstName) from DemoTable1905;
ผลลัพธ์:
+---------------------------+ | count(distinct FirstName) | +---------------------------+ | 3 | +---------------------------+ 1 row in set (0.00 sec)
ทำไม INDEX ช่วยได้?
- Index เก็บค่าที่เรียงลำดับแล้ว → MySQL สแกน Index แทน Full Table Scan
- Composite Index
(FirstName, LastName)ช่วยทั้งCOUNT(DISTINCT FirstName)และCOUNT(DISTINCT FirstName, LastName) - MySQL ใช้
Loose Index Scanสำหรับ DISTINCT บน Index
เทคนิคเพิ่มเติมสำหรับ COUNT DISTINCT ช้า
| วิธี | คำอธิบาย | Trade-off |
|---|---|---|
| เพิ่ม INDEX | CREATE INDEX idx_col ON table(col) | ช่วย SELECT ช้า INSERT/UPDATE |
| Summary Table | สร้างตารางสรุปไว้ล่วงหน้า | ต้อง Maintain เอง |
| APPROX_COUNT_DISTINCT | MySQL 8.0.13+ ใช้ HyperLogLog | ประมาณการ ไม่แม่นยำ 100% |
| Partitioning | แบ่ง Partition ตามคอลัมน์ | ซับซ้อน ต้องวางแผน |
ใช้ APPROX_COUNT_DISTINCT (MySQL 8.0.13+)
SELECT APPROX_COUNT_DISTINCT(FirstName) FROM DemoTable1905;
สรุป: สร้าง INDEX บนคอลัมน์ที่ใช้ COUNT(DISTINCT ...) บ่อย ๆ จะเร่งความเร็วได้มาก สำหรับข้อมูลใหญ่มาก พิจารณา APPROX_COUNT_DISTINCT หรือ Summary Table