- 1 1. บทนำ
- 2 2. ROW_NUMBER() คืออะไร?
- 3 3. กรณีการใช้งานจริง
- 4 4. การเปรียบเทียบกับ Window Functions อื่นๆ
- 5 5. ทางเลือกสำหรับ MySQL เวอร์ชันต่ำกว่า 8.0
- 6 6. ข้อควรระวังและแนวปฏิบัติที่ดี
- 7 7. Conclusion
1. บทนำ
MySQL เวอร์ชัน 8.0 ได้นำเสนอคุณลักษณะใหม่หลายอย่าง และหนึ่งในคุณลักษณะที่โดดเด่นคือการสนับสนุนฟังก์ชันหน้าต่าง (window functions) ในบทความนี้ เราจะเน้นไปที่หนึ่งในฟังก์ชันที่ใช้บ่อยที่สุดคือ ROW_NUMBER().
ฟังก์ชัน ROW_NUMBER() ให้ความสามารถที่ทรงพลังสำหรับการวิเคราะห์ข้อมูลและการรายงาน ทำให้การจัดเรียงและจัดอันดับข้อมูลตามเงื่อนไขเฉพาะเป็นเรื่องง่าย บทความนี้จะอธิบายทุกอย่างตั้งแต่การใช้งานพื้นฐาน ตัวอย่างเชิงปฏิบัติ ไปจนถึงวิธีการทางเลือกสำหรับ MySQL เวอร์ชันเก่า.
กลุ่มผู้อ่านเป้าหมาย
- ผู้ใช้ระดับเริ่มต้นถึงระดับกลางที่มีความรู้พื้นฐานเกี่ยวกับ SQL
- วิศวกรและนักวิเคราะห์ข้อมูลที่ประมวลผลและวิเคราะห์ข้อมูลด้วย MySQL
- ผู้ที่กำลังพิจารณาอัปเกรดไปยังเวอร์ชันล่าสุดของ MySQL
ประโยชน์ของ ROW_NUMBER()
ฟังก์ชันนี้ช่วยให้คุณกำหนดหมายเลขที่ไม่ซ้ำกันให้กับแต่ละแถวตามเงื่อนไขที่กำหนด ตัวอย่างเช่น คุณสามารถเขียนคิวรีอย่าง “สร้างการจัดอันดับตามลำดับลดลงของยอดขาย” หรือ “ดึงและจัดระเบียบข้อมูลที่ซ้ำกัน” ได้อย่างกระชับ.
ในเวอร์ชันเก่า คุณมักต้องเขียนคิวรีที่ซับซ้อนโดยใช้ตัวแปรที่กำหนดโดยผู้ใช้ ด้วย ROW_NUMBER() SQL ของคุณจะง่ายขึ้นและอ่านง่ายขึ้น.
ในบทความนี้ เราจะใช้ตัวอย่างคิวรีที่เป็นรูปธรรมและอธิบายอย่างเป็นมิตรต่อผู้เริ่มต้น ในส่วนต่อไป เราจะเจาะลึกไวยากรณ์พื้นฐานและพฤติกรรมของฟังก์ชันนี้.
2. ROW_NUMBER() คืออะไร?
ฟังก์ชัน ROW_NUMBER() ที่เพิ่มเข้ามาใหม่ใน MySQL 8.0 เป็นประเภทของฟังก์ชันหน้าต่างที่กำหนดหมายเลขลำดับให้กับแถว สามารถกำหนดหมายเลขแถวตามลำดับที่ระบุและ/หรือภายในแต่ละกลุ่ม ซึ่งมีประโยชน์อย่างยิ่งสำหรับการวิเคราะห์ข้อมูลและการรายงาน ที่นี่เราจะอธิบายไวยากรณ์พื้นฐานอย่างละเอียดพร้อมตัวอย่างเชิงปฏิบัติ.
ไวยากรณ์พื้นฐานของ ROW_NUMBER()
ก่อนอื่น รูปแบบพื้นฐานของ ROW_NUMBER() มีดังต่อไปนี้.
SELECT
column_name,
ROW_NUMBER() OVER (PARTITION BY group_column ORDER BY sort_column) AS row_num
FROM
table_name;
ความหมายของแต่ละส่วน
- ROW_NUMBER() : กำหนดหมายเลขลำดับให้กับแต่ละแถว.
- OVER : คำสำคัญที่ใช้กำหนดหน้าต่างสำหรับฟังก์ชันหน้าต่าง.
- PARTITION BY : จัดกลุ่มข้อมูลตามคอลัมน์ที่ระบุ เป็นตัวเลือก หากละเว้น การกำหนดหมายเลขจะทำทั่วทั้งแถว.
- ORDER BY : กำหนดลำดับที่ใช้ในการกำหนดหมายเลข คือเกณฑ์การจัดเรียง.
ตัวอย่างพื้นฐาน
ตัวอย่างเช่น สมมติว่าคุณมีตารางชื่อ “sales” ที่มีข้อมูลดังต่อไปนี้.
| employee | department | sale |
|---|---|---|
| A | Sales Department | 500 |
| B | Sales Department | 800 |
| C | Development Department | 600 |
| D | Development Department | 700 |
เพื่อกำหนดหมายเลขลำดับภายในแต่ละแผนกตามลำดับลดลงของยอดขาย ให้ใช้คิวรีต่อนี้.
SELECT
employee,
department,
sale,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY sale DESC) AS row_num
FROM
sales;
ผลลัพธ์
| employee | department | sale | row_num |
|---|---|---|---|
| B | Sales Department | 800 | 1 |
| A | Sales Department | 500 | 2 |
| D | Development Department | 700 | 1 |
| C | Development Department | 600 | 2 |
จากผลลัพธ์นี้ คุณจะเห็นว่า การจัดอันดับตามยอดขายภายในแต่ละแผนกถูกแสดงออก.
วิธีใช้ PARTITION BY
ในตัวอย่างข้างต้น ข้อมูลถูกจัดกลุ่มตามคอลัมน์ “department” ซึ่งทำให้แต่ละแผนกมีลำดับแยกกัน.
หากคุณละเว้น PARTITION BY การกำหนดหมายเลขจะทำทั่วทั้งแถวเป็นลำดับเดียว.
SELECT
employee,
sale,
ROW_NUMBER() OVER (ORDER BY sale DESC) AS row_num
FROM
sales;
ผลลัพธ์
| employee | sale | row_num |
|---|---|---|
| B | 800 | 1 |
| D | 700 | 2 |
| C | 600 | 3 |
| A | 500 | 4 |
คุณลักษณะและข้อควรระวังของ ROW_NUMBER()
- Unique numbering : แม้ค่าจะเท่ากัน หมายเลขที่กำหนดก็ยังเป็นเอกลักษณ์.
- Handling NULLs : หาก ORDER BY มีค่า NULL จะปรากฏเป็นอันดับแรกในลำดับเพิ่มและเป็นอันดับสุดท้ายในลำดับลด.
- Performance impact : สำหรับชุดข้อมูลขนาดใหญ่ ORDER BY อาจทำให้ประสิทธิภาพลดลง ดังนั้นการสร้างดัชนีที่เหมาะสมจึงสำคัญ.
3. กรณีการใช้งานจริง
ต่อไปนี้เป็นสถานการณ์การใช้งานจริงของฟังก์ชัน ROW_NUMBER() ของ MySQL ฟังก์ชันนี้มีประโยชน์ในหลายกรณีจริง เช่น การจัดอันดับข้อมูลและการจัดการข้อมูลซ้ำ.
3-1. การจัดอันดับภายในแต่ละกลุ่ม
ตัวอย่างเช่น พิจารณากรณีที่คุณต้องการ “จัดอันดับพนักงานตามยอดขายภายในแต่ละแผนก” โดยใช้ข้อมูลยอดขาย ใช้ชุดข้อมูลต่อไปนี้เป็นตัวอย่าง
| employee | department | sale |
|---|---|---|
| A | Sales Department | 500 |
| B | Sales Department | 800 |
| C | Development Department | 600 |
| D | Development Department | 700 |
ตัวอย่างคำสั่ง: การจัดอันดับยอดขายตามแผนก
SELECT
employee,
department,
sale,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY sale DESC) AS rank
FROM
sales;
ผลลัพธ์:
| employee | department | sale | rank |
|---|---|---|---|
| B | Sales Department | 800 | 1 |
| A | Sales Department | 500 | 2 |
| D | Development Department | 700 | 1 |
| C | Development Department | 600 | 2 |
ในลักษณะนี้ แต่ละแผนกจะได้รับลำดับของตัวเองในลำดับยอดขายจากมากไปน้อย ทำให้ง่ายต่อการสร้างอันดับ
3-2. การดึงแถว Top N
ต่อไป ลองดูกรณีที่คุณต้องการ “ดึงพนักงาน top 3 ตามยอดขายภายในแต่ละแผนก”
ตัวอย่างคำสั่ง: ดึงแถว Top N
WITH RankedSales AS (
SELECT
employee,
department,
sale,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY sale DESC) AS rank
FROM
sales
)
SELECT
employee,
department,
sale
FROM
RankedSales
WHERE
rank <= 3;
ผลลัพธ์:
| employee | department | sale |
|---|---|---|
| B | Sales Department | 800 |
| A | Sales Department | 500 |
| D | Development Department | 700 |
| C | Development Department | 600 |
ตัวอย่างนี้จะดึงเฉพาะแถว top 3 ตามยอดขายภายในแต่ละแผนก ดังที่เห็น ROW_NUMBER() ไม่เพียงเหมาะสำหรับการจัดอันดับเท่านั้น แต่ยังเหมาะสำหรับการกรองผลลัพธ์ชั้นนำด้วย
3-3. การค้นหาและลบข้อมูลซ้ำ
ฐานข้อมูลบางครั้งอาจมีเรคคอร์ดซ้ำกัน ในกรณีเช่นนี้ คุณสามารถจัดการได้อย่างง่ายดายโดยใช้ ROW_NUMBER()
ตัวอย่างคำสั่ง: ตรวจจับข้อมูลซ้ำ
SELECT *
FROM (
SELECT
employee,
sale,
ROW_NUMBER() OVER (PARTITION BY employee ORDER BY sale DESC) AS rank
FROM
sales
) tmp
WHERE rank > 1;
คำสั่งนี้จะตรวจจับข้อมูลซ้ำเมื่อมีเรคคอร์ดหลายรายการสำหรับชื่อพนักงานเดียวกัน
ตัวอย่างคำสั่ง: ลบข้อมูลซ้ำ
DELETE FROM sales
WHERE id IN (
SELECT id
FROM (
SELECT
id,
ROW_NUMBER() OVER (PARTITION BY employee ORDER BY sale DESC) AS rank
FROM
sales
) tmp
WHERE rank > 1
);
สรุป
ROW_NUMBER() มีประโยชน์ในสถานการณ์หลากหลาย เช่น:
- การจัดอันดับภายในแต่ละกลุ่ม
- การดึงแถว Top N
- การตรวจจับและลบข้อมูลซ้ำ
สิ่งนี้ทำให้การประมวลผลและวิเคราะห์ข้อมูลที่ซับซ้อนง่ายและมีประสิทธิภาพยิ่งขึ้น
4. การเปรียบเทียบกับ Window Functions อื่นๆ
ใน MySQL 8.0 นอกจาก ROW_NUMBER() แล้ว ยังมี window functions เช่น RANK() และ DENSE_RANK() ที่สามารถใช้สำหรับการจัดอันดับและการคำนวณตำแหน่งได้ แม้ว่าพวกมันจะมีบทบาทคล้ายกัน แต่พฤติกรรมและผลลัพธ์ต่างกัน ที่นี่เราจะเปรียบเทียบแต่ละฟังก์ชันและอธิบายว่าควรใช้เมื่อใด
4-1. ฟังก์ชัน RANK()
ฟังก์ชัน RANK() จะกำหนดอันดับ โดยให้อันดับเดียวกันกับค่าที่เท่ากันและข้ามหมายเลขอันดับถัดไป
ไวยากรณ์พื้นฐาน
SELECT
column_name,
RANK() OVER (PARTITION BY group_column ORDER BY sort_column) AS rank
FROM
table_name;
ตัวอย่าง
โดยใช้ข้อมูลต่อไปนี้ คำนวณอันดับยอดขาย
| employee | department | sale |
|---|---|---|
| A | Sales Department | 800 |
| B | Sales Department | 800 |
| C | Sales Department | 600 |
| D | Sales Department | 500 |
ตัวอย่างคำสั่ง: ใช้ RANK()
SELECT
employee,
sale,
RANK() OVER (ORDER BY sale DESC) AS rank
FROM
sales;
ผลลัพธ์:
| employee | sale | rank |
|---|---|---|
| A | 800 | 1 |
| B | 800 | 1 |
| C | 600 | 3 |
| D | 500 | 4 |
ประเด็นสำคัญ:
- A และ B ที่มียอดขายเท่ากัน (800) จะถูกจัดการเป็นอันดับ “1” ทั้งคู่
- อันดับถัดไป “2” ถูกข้าม ดังนั้น C จึงกลายเป็นอันดับ “3”
4-2. ฟังก์ชัน DENSE_RANK()
ฟังก์ชัน DENSE_RANK() ก็กำหนดอันดับเดียวกันกับค่าที่เท่ากันเช่นกัน แต่ไม่ข้ามหมายเลขอันดับถัดไป
ไวยากรณ์พื้นฐาน
SELECT
column_name,
DENSE_RANK() OVER (PARTITION BY group_column ORDER BY sort_column) AS dense_rank
FROM
table_name;
ตัวอย่าง
โดยใช้ข้อมูลเดียวกันกับด้านบน ลองใช้ฟังก์ชัน DENSE_RANK()
ตัวอย่างคำสั่ง: ใช้ DENSE_RANK()
SELECT
employee,
sale,
DENSE_RANK() OVER (ORDER BY sale DESC) AS dense_rank
FROM
sales;
ผลลัพธ์:
| employee | sale | dense_rank |
|---|---|---|
| A | 800 | 1 |
| B | 800 | 1 |
| C | 600 | 2 |
| D | 500 | 3 |
ประเด็นสำคัญ:
- A และ B ที่มีจำนวนการขายเท่ากัน (800) จะถูกจัดเป็นอันดับ “1”.
- แตกต่างจาก RANK() ขั้นต่อไปเริ่มที่ “2” ดังนั้นความต่อเนื่องของอันดับจะถูกเก็บไว้.
4-3. วิธีที่ ROW_NUMBER() แตกต่าง
ฟังก์ชัน ROW_NUMBER() แตกต่างจากสองฟังก์ชันอื่นโดยจะ กำหนดหมายเลขที่ไม่ซ้ำกัน แม้ค่าจะเท่ากัน
ตัวอย่าง
SELECT
employee,
sale,
ROW_NUMBER() OVER (ORDER BY sale DESC) AS row_num
FROM
sales;
ผลลัพธ์:
| employee | sale | row_num |
|---|---|---|
| A | 800 | 1 |
| B | 800 | 2 |
| C | 600 | 3 |
| D | 500 | 4 |
ประเด็นสำคัญ:
- แม้ว่าค่าจะเท่ากัน แต่แต่ละแถวจะได้รับหมายเลขที่ไม่ซ้ำกัน ดังนั้นจึงไม่มีอันดับซ้ำ.
- สิ่งนี้มีประโยชน์เมื่อคุณต้องการการควบคุมการเรียงลำดับอย่างเคร่งครัดหรือความไม่ซ้ำกันต่อแถว.
4-4. สรุปกรณีการใช้งานอย่างรวดเร็ว
| Function | Ranking behavior | Typical use case |
|---|---|---|
| ROW_NUMBER() | Assigns a unique number | When you need sequential numbering or unique identification per row |
| RANK() | Same rank for ties; skips the next rank number | When you want rankings with gaps reflecting ties |
| DENSE_RANK() | Same rank for ties; does not skip rank numbers | When you want continuous ranks without gaps |
สรุป
ROW_NUMBER(), RANK(), และ DENSE_RANK() ควรใช้ตามความเหมาะสมขึ้นอยู่กับสถานการณ์.
- ROW_NUMBER() เหมาะที่สุดเมื่อคุณต้องการหมายเลขที่ไม่ซ้ำกันต่อแถว.
- RANK() มีประโยชน์เมื่อคุณต้องการให้ค่าที่เท่ากันแชร์อันดับเดียวกันและต้องการเน้นช่องว่างของอันดับ.
- DENSE_RANK() เหมาะเมื่อคุณต้องการอันดับต่อเนื่องโดยไม่มีช่องว่าง.

5. ทางเลือกสำหรับ MySQL เวอร์ชันต่ำกว่า 8.0
ในเวอร์ชันก่อน MySQL 8.0, ROW_NUMBER() และฟังก์ชันหน้าต่างอื่น ๆ ไม่ได้รับการสนับสนุน อย่างไรก็ตาม คุณสามารถทำพฤติกรรมคล้ายกันโดยใช้ตัวแปรที่กำหนดโดยผู้ใช้ ส่วนนี้อธิบายทางเลือกที่ใช้งานได้จริงสำหรับ MySQL เวอร์ชันต่ำกว่า 8.0.
5-1. การกำหนดลำดับเลขต่อเนื่องโดยใช้ตัวแปรที่กำหนดโดยผู้ใช้
ใน MySQL 5.7 และก่อนหน้า คุณสามารถใช้ตัวแปรที่กำหนดโดยผู้ใช้เพื่อกำหนดหมายเลขต่อเนื่องต่อแถว มาดูตัวอย่างต่อไปนี้.
ตัวอย่าง: การจัดอันดับการขายตามแผนก
ข้อมูลตัวอย่าง:
| employee | department | sale |
|---|---|---|
| A | Sales Department | 500 |
| B | Sales Department | 800 |
| C | Development Department | 600 |
| D | Development Department | 700 |
คำสั่ง:
SET @row_num = 0;
SET @dept = '';
SELECT
employee,
department,
sale,
@row_num := IF(@dept = department, @row_num + 1, 1) AS rank,
@dept := department
FROM
(SELECT * FROM sales ORDER BY department, sale DESC) AS sorted_sales;
ผลลัพธ์:
| employee | department | sale | rank |
|---|---|---|---|
| B | Sales Department | 800 | 1 |
| A | Sales Department | 500 | 2 |
| D | Development Department | 700 | 1 |
| C | Development Department | 600 | 2 |
5-2. การดึงแถว Top N
เพื่อดึงแถว Top N คุณสามารถใช้ตัวแปรที่กำหนดโดยผู้ใช้ในลักษณะเดียวกัน.
คำสั่ง:
SET @row_num = 0;
SET @dept = '';
SELECT *
FROM (
SELECT
employee,
department,
sale,
@row_num := IF(@dept = department, @row_num + 1, 1) AS rank,
@dept := department
FROM
(SELECT * FROM sales ORDER BY department, sale DESC) AS sorted_sales
) AS ranked_sales
WHERE rank <= 3;
ผลลัพธ์:
| employee | department | sale | rank |
|---|---|---|---|
| B | Sales Department | 800 | 1 |
| A | Sales Department | 500 | 2 |
| D | Development Department | 700 | 1 |
| C | Development Department | 600 | 2 |
คำสั่งนี้กำหนดอันดับตามแผนกและจากนั้นดึงเฉพาะแถวที่อยู่ในอันดับ 3 แรก.
5-3. การตรวจจับและลบข้อมูลซ้ำ
คุณยังสามารถจัดการข้อมูลซ้ำโดยใช้ตัวแปรที่กำหนดโดยผู้ใช้.
ตัวอย่างคำสั่ง: ตรวจจับข้อมูลซ้ำ
SET @row_num = 0;
SET @id_check = '';
SELECT *
FROM (
SELECT
id,
name,
@row_num := IF(@id_check = name, @row_num + 1, 1) AS rank,
@id_check := name
FROM
(SELECT * FROM customers ORDER BY name, id) AS sorted_customers
) AS tmp
WHERE rank > 1;
ตัวอย่างคำสั่ง: ลบข้อมูลซ้ำ
DELETE FROM customers
WHERE id IN (
SELECT id
FROM (
SELECT
id,
@row_num := IF(@id_check = name, @row_num + 1, 1) AS rank,
@id_check := name
FROM
(SELECT * FROM customers ORDER BY name, id) AS sorted_customers
) AS tmp
WHERE rank > 1
);
5-4. ข้อควรระวังเมื่อใช้ตัวแปรที่กำหนดโดยผู้ใช้
- การพึ่งพาเซสชัน
- ตัวแปรที่กำหนดโดยผู้ใช้มีผลเฉพาะภายในเซสชันปัจจุบัน ไม่สามารถนำกลับมาใช้ใหม่ในคำสั่งหรือเซสชันอื่นได้.
- การพึ่งพาลำดับการประมวลผล
- ตัวแปรที่กำหนดโดยผู้ใช้ขึ้นกับลำดับการทำงาน ดังนั้นการกำหนด ORDER BY อย่างเหมาะสมจึงสำคัญ.
- ความอ่านง่ายและการบำรุงรักษาของ SQL
- คำสั่งอาจซับซ้อนขึ้น ดังนั้นใน MySQL 8.0 ขึ้นไป แนะนำให้ใช้ฟังก์ชันหน้าต่าง.
สรุป
ในเวอร์ชัน MySQL ที่ต่ำกว่า 8.0 คุณสามารถใช้ตัวแปรที่กำหนดโดยผู้ใช้เพื่อนำเสนอการเรียงลำดับหมายเลขต่อเนื่องและการจัดอันดับแทนฟังก์ชันหน้าต่าง อย่างไรก็ตาม เนื่องจากคำสั่งค้นหามักจะซับซ้อนมากขึ้น จึงควรพิจารณาย้ายไปยังเวอร์ชันที่ใหม่กว่าเมื่อเป็นไปได้
6. ข้อควรระวังและแนวปฏิบัติที่ดี
ฟังก์ชัน ROW_NUMBER() ของ MySQL และทางเลือกที่ใช้ตัวแปรนั้นสะดวกมาก แต่มีประเด็นสำคัญที่ต้องจำไว้เพื่อให้ทำงานได้อย่างถูกต้องและมีประสิทธิภาพส่วนนี้จะอธิบายข้อควรระวังทางปฏิบัติและแนวปฏิบัติที่ดีที่สุดสำหรับการปรับแต่งประสิทธิภาพ
6-1. ข้อพิจารณาเกี่ยวกับประสิทธิภาพ
1. ต้นทุนของ ORDER BY
ROW_NUMBER() จะถูกใช้เสมอพร้อมกับ ORDER BY เนื่องจากต้องทำการเรียงลำดับ เวลาการประมวลผลจึงอาจเพิ่มขึ้นอย่างมีนัยสำคัญสำหรับชุดข้อมูลขนาดใหญ่
การบรรเทา:
- ใช้ดัชนี: เพิ่มดัชนีให้กับคอลัมน์ที่ใช้ใน ORDER BY เพื่อเร่งความเร็วในการเรียงลำดับ
- ใช้ LIMIT: ดึงเฉพาะจำนวนแถวที่ต้องการจริงเพื่อลดปริมาณข้อมูลที่ประมวลผล
ตัวอย่าง:
SELECT
employee,
sale,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY sale DESC) AS rank
FROM
sales
LIMIT 1000;
2. การใช้งานหน่วยความจำที่เพิ่มขึ้นและ I/O ของดิสก์
ฟังก์ชันหน้าต่างจะถูกประมวลผลโดยใช้ตารางชั่วคราวและหน่วยความจำ เมื่อปริมาณข้อมูลเพิ่มขึ้น การใช้หน่วยความจำและ I/O ของดิสก์ก็จะเพิ่มขึ้น
การบรรเทา:
- แยกคำสั่งค้นหา: แยกการประมวลผลออกเป็นคำสั่งค้นหาขนาดเล็กกว่าและดึงข้อมูลทีละขั้นตอนเพื่อลดภาระ
- ใช้ตารางชั่วคราว: เก็บข้อมูลที่ดึงออกมาในตารางชั่วคราวและรันการรวมจากที่นั่นเพื่อกระจายภาระงาน
6-2. เคล็ดลับการปรับแต่งคำสั่งค้นหา
1. ตรวจสอบแผนการรัน
ใน MySQL คุณสามารถใช้ EXPLAIN เพื่อตรวจสอบแผนการรันคำสั่งค้นหา สิ่งนี้ช่วยให้คุณยืนยันว่าดัชนีถูกใช้อย่างถูกต้องหรือไม่
ตัวอย่าง:
EXPLAIN
SELECT
employee,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY sale DESC) AS rank
FROM
sales;
ผลลัพธ์ตัวอย่าง:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|---|---|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | sales | index | NULL | sale | 4 | NULL | 500 | Using index |
หากคุณเห็น Using index แสดงว่าดัชนีถูกใช้อย่างเหมาะสม
2. ปรับแต่งดัชนี
โปรดแน่ใจว่าเพิ่มดัชนีให้กับคอลัมน์ที่ใช้ใน ORDER BY และ WHERE ให้ความสนใจเป็นพิเศษกับสิ่งต่อไปนี้
- ดัชนีคอลัมน์เดียว: ดีสำหรับเงื่อนไขการเรียงลำดับแบบง่าย
- ดัชนีรวม: มีประสิทธิภาพเมื่อมีคอลัมน์หลายคอลัมน์ที่เกี่ยวข้องกับเงื่อนไข
ตัวอย่าง:
CREATE INDEX idx_department_sale ON sales(department, sale DESC);
3. ใช้การประมวลผลแบบแบทช์
แทนที่จะประมวลผลชุดข้อมูลขนาดใหญ่ทั้งหมดในครั้งเดียว คุณสามารถลดภาระโดยการประมวลผลข้อมูลเป็นแบทช์
ตัวอย่าง:
SELECT * FROM sales WHERE department = 'Sales Department' LIMIT 1000 OFFSET 0;
SELECT * FROM sales WHERE department = 'Sales Department' LIMIT 1000 OFFSET 1000;
6-3. การรักษาความสอดคล้องของข้อมูล
1. การอัปเดตและการคำนวณใหม่
เมื่อแทรกหรือลบแถว การเรียงลำดับหมายเลขอาจเปลี่ยนแปลง สร้างกลไกเพื่อคำนวณหมายเลขใหม่ตามที่จำเป็น
ตัวอย่าง:
CREATE VIEW ranked_sales AS
SELECT
employee,
sale,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY sale DESC) AS rank
FROM
sales;
การใช้มุมมองช่วยให้คุณรักษาการจัดอันดับให้ทันสมัยตามข้อมูลล่าสุด
6-4. ตัวอย่างคำสั่งค้นหาตามแนวปฏิบัติที่ดีที่สุด
ด้านล่างนี้คือตัวอย่างของแนวปฏิบัติที่ดีที่สุดที่พิจารณาประสิทธิภาพและความสามารถในการบำรุงรักษา
ตัวอย่าง: ดึงแถว Top N
WITH RankedSales AS (
SELECT
employee,
department,
sale,
ROW_NUMBER() OVER (PARTITION BY department ORDER BY sale DESC) AS rank
FROM
sales
)
SELECT *
FROM RankedSales
WHERE rank <= 3;
โครงสร้างนี้ใช้การแสดงออกตารางร่วม (CTE) เพื่อปรับปรุงความสามารถในการอ่านและการนำกลับมาใช้ใหม่
สรุป
เมื่อใช้ ROW_NUMBER() หรือทางเลือกของมัน โปรดจำประเด็นเหล่านี้ไว้:
- ปรับปรุงความเร็วด้วย การเพิ่มประสิทธิภาพดัชนี .
- ระบุคอขวดโดยตรวจสอบ แผนการดำเนินการ .
- วางแผนสำหรับ การอัปเดตข้อมูล และรักษาความสอดคล้อง.
- ใช้ การประมวลผลแบบแบตช์ และ CTEs เพื่อกระจายภาระงาน.
การนำแนวปฏิบัติที่ดีที่สุดเหล่านี้ไปใช้จะทำให้การประมวลผลสำหรับการวิเคราะห์และการรายงานข้อมูลขนาดใหญ่มีประสิทธิภาพ.
7. Conclusion
ในบทความนี้ เราได้มุ่งเน้นที่ฟังก์ชัน ROW_NUMBER() ของ MySQL โดยอธิบายทุกอย่างตั้งแต่การใช้งานพื้นฐานและตัวอย่างเชิงปฏิบัติจนถึงทางเลือกสำหรับเวอร์ชันเก่า รวมถึงข้อควรระวังและแนวปฏิบัติที่ดีที่สุด ในส่วนนี้ เราจะสรุปประเด็นสำคัญและสรุปข้อสรุปเชิงปฏิบัติ.
7-1. Why ROW_NUMBER() is useful
ฟังก์ชัน ROW_NUMBER() มีความสะดวกเป็นพิเศษสำหรับการวิเคราะห์และการรายงานข้อมูลในวิธีต่อไปนี้:
- การจัดลำดับเลขต่อเนื่องภายในกลุ่ม: สร้างอันดับการขายตามแผนกหรือหมวดหมู่ได้อย่างง่ายดาย.
- การดึงแถว Top N: กรองและดึงข้อมูลตามเงื่อนไขเฉพาะอย่างมีประสิทธิภาพ.
- การตรวจจับและลบข้อมูลซ้ำ: มีประโยชน์สำหรับการทำความสะอาดและจัดระเบียบข้อมูล.
เนื่องจากมันทำให้คิวรีที่ซับซ้อนง่ายขึ้น จึงปรับปรุงความอ่านง่ายและการบำรุงรักษาของ SQL อย่างมีนัยสำคัญ.
7-2. Comparison with other window functions
เมื่อเทียบกับฟังก์ชันหน้าต่างเช่น RANK() และ DENSE_RANK() ฟังก์ชัน ROW_NUMBER() แตกต่างกันตรงที่มันกำหนดหมายเลขที่ไม่ซ้ำแม้ค่าจะเท่ากัน.
| Function | Feature | Use case |
|---|---|---|
| ROW_NUMBER() | Assigns a unique sequential number to each row | Best when you need unique identification or ranking with no duplicates |
| RANK() | Same rank for ties; skips the next rank number | When you need tie-aware rankings and rank gaps matter |
| DENSE_RANK() | Same rank for ties; does not skip rank numbers | When you want continuous ranking while handling ties |
การเลือกฟังก์ชันที่เหมาะสม:
การเลือกฟังก์ชันที่ดีที่สุดสำหรับวัตถุประสงค์ของคุณทำให้การประมวลผลข้อมูลมีประสิทธิภาพ.
7-3. Handling older MySQL versions
สำหรับสภาพแวดล้อมที่ต่ำกว่า MySQL 8.0 เราได้แนะนำวิธีการใช้ตัวแปรที่กำหนดโดยผู้ใช้ อย่างไรก็ตาม คุณควรพิจารณาข้อควรระวังต่อไปนี้:
- ความอ่านง่ายลดลงเนื่องจาก SQL ที่ซับซ้อนมากขึ้น
- การปรับแต่งคิวรีอาจยากขึ้นในบางกรณี
- อาจต้องมีการจัดการเพิ่มเติมเพื่อรักษาความสอดคล้องของข้อมูล
หากเป็นไปได้ ควรพิจารณาอัปเกรดเป็น MySQL 8.0 หรือใหม่กว่าและใช้ฟังก์ชันหน้าต่าง.
7-4. Key points for performance optimization
- ใช้ดัชนี: เพิ่มดัชนีให้กับคอลัมน์ที่ใช้ใน ORDER BY เพื่อปรับปรุงความเร็ว.
- ตรวจสอบแผนการดำเนินการ: ตรวจสอบประสิทธิภาพล่วงหน้าด้วย EXPLAIN.
- นำการประมวลผลแบบแบตช์มาใช้: ประมวลผลชุดข้อมูลขนาดใหญ่เป็นชิ้นย่อยเพื่อกระจายภาระ.
- ใช้วิวและ CTEs: ปรับปรุงการนำกลับมาใช้ใหม่และทำให้คิวรีที่ซับซ้อนง่ายขึ้น.
โดยการใช้เทคนิคเหล่านี้ คุณสามารถบรรลุการประมวลผลข้อมูลที่มีประสิทธิภาพและเสถียร.
7-5. Final notes
ROW_NUMBER() เป็นเครื่องมือที่ทรงพลังซึ่งสามารถปรับปรุงประสิทธิภาพของการวิเคราะห์ข้อมูลได้อย่างมีนัยสำคัญ.
ในบทความนี้ เราได้ครอบคลุมทุกอย่างตั้งแต่ไวยากรณ์พื้นฐานและตัวอย่างเชิงปฏิบัติจนถึงข้อควรระวังและทางเลือก.
เราขอแนะนำให้คุณรันคิวรีด้วยตนเองพร้อมกับอ่านบทความนี้ การพัฒนาทักษะ SQL ของคุณจะช่วยให้คุณรับมือกับการวิเคราะห์และการรายงานข้อมูลที่ซับซ้อนมากขึ้นด้วยความมั่นใจ.
Appendix: Reference resources
- เอกสารอย่างเป็นทางการ: MySQL Window Functions
- สภาพแวดล้อม SQL ออนไลน์: SQL Fiddle (เครื่องมือที่ให้คุณรันและทดสอบ SQL ออนไลน์)


