MySQL 中 ROW_NUMBER() 函數(shù)最佳實(shí)踐
MySQL 中 ROW_NUMBER() 函數(shù)詳解
ROW_NUMBER() 是 SQL 窗口函數(shù)中的一種,用于為查詢結(jié)果集中的每一行分配一個??唯一的連續(xù)序號??。與 RANK() 和 DENSE_RANK() 不同,ROW_NUMBER() 不會處理重復(fù)值,即使排序字段值相同,也會嚴(yán)格按行順序遞增編號。
一、基礎(chǔ)語法
ROW_NUMBER() OVER (
[PARTITION BY 分組字段]
ORDER BY 排序字段 [ASC|DESC]
)- ??PARTITION BY??:按指定字段分組,每組內(nèi)重新從1開始編號。
- ??ORDER BY??:決定排序邏輯,影響行號的分配順序。
二、核心特點(diǎn)
| ??特性?? | ??說明?? |
|---|---|
| 唯一性 | 每行序號嚴(yán)格遞增,不重復(fù)(即使排序字段值相同) |
| 靈活性 | 可結(jié)合分組(PARTITION BY)實(shí)現(xiàn)復(fù)雜場景 |
| 兼容性 | MySQL 8.0+ 原生支持,低版本需用變量模擬 |
| 性能影響 | 未優(yōu)化時可能導(dǎo)致全表掃描,需合理使用索引 |
三、典型應(yīng)用場景
1. 數(shù)據(jù)分頁查詢
-- 查詢第3頁數(shù)據(jù)(每頁10條)
WITH paged_data AS (
SELECT
id, name,
ROW_NUMBER() OVER (ORDER BY id) AS row_num
FROM users
)
SELECT *
FROM paged_data
WHERE row_num BETWEEN 21 AND 30;2. 刪除重復(fù)數(shù)據(jù)
-- 保留最新記錄(假設(shè) create_time 為時間戳)
DELETE FROM orders
WHERE (id, product_id) IN (
SELECT id, product_id FROM (
SELECT
id, product_id,
ROW_NUMBER() OVER (
PARTITION BY product_id
ORDER BY create_time DESC
) AS rn
FROM orders
) t
WHERE rn > 1 -- 刪除重復(fù)項,保留最新一條
);3. 分組取Top N記錄
-- 獲取每個部門薪資前3名
SELECT *
FROM (
SELECT
name, department, salary,
ROW_NUMBER() OVER (
PARTITION BY department
ORDER BY salary DESC
) AS dept_rank
FROM employees
) ranked
WHERE dept_rank <= 3;4. 生成唯一流水號
-- 按日期生成訂單流水號(格式:YYYYMMDD-0001)
SELECT
order_id,
CONCAT(
DATE_FORMAT(create_time, '%Y%m%d'),
'-',
LPAD(ROW_NUMBER() OVER (
PARTITION BY DATE(create_time)
ORDER BY create_time
), 4, '0')
) AS serial_num
FROM orders;四、與其他排序函數(shù)對比
| 函數(shù) | 重復(fù)值處理 | 示例結(jié)果(排序字段值相同) |
|---|---|---|
ROW_NUMBER() | 強(qiáng)制分配不同序號 | 1, 2, 3, 4 |
RANK() | 相同值共享排名,后續(xù)跳過序號 | 1, 1, 3, 4 |
DENSE_RANK() | 相同值共享排名,后續(xù)連續(xù)遞增 | 1, 1, 2, 3 |
-- 對比三種函數(shù)
SELECT
score,
ROW_NUMBER() OVER (ORDER BY score DESC) AS row_num,
RANK() OVER (ORDER BY score DESC) AS rank,
DENSE_RANK() OVER (ORDER BY score DESC) AS dense_rank
FROM exam_scores;五、性能優(yōu)化技巧
1. 索引設(shè)計
為 PARTITION BY 和 ORDER BY 涉及的字段創(chuàng)建聯(lián)合索引:
CREATE INDEX idx_dept_salary ON employees(department, salary DESC);
2. 減少計算范圍
-- 僅處理2023年數(shù)據(jù)
SELECT *
FROM (
SELECT
order_id, amount,
ROW_NUMBER() OVER (ORDER BY amount DESC) AS rn
FROM orders
WHERE YEAR(order_date) = 2023 -- 先過濾再排序
) t
WHERE rn <= 100;3. 避免嵌套查詢
-- 優(yōu)化前(性能差)
SELECT * FROM (
SELECT *, ROW_NUMBER() OVER (...) AS rn
FROM large_table
) t WHERE rn <= 100;
-- 優(yōu)化后(直接使用LIMIT,若邏輯允許)
SELECT *, ROW_NUMBER() OVER (...) AS rn
FROM large_table
ORDER BY ...
LIMIT 100;六、MySQL低版本兼容方案(5.7及以下)
使用會話變量模擬 ROW_NUMBER()
-- 按部門分組排序
SELECT
department, name, salary,
@row_num := IF(
@current_dept = department,
@row_num + 1,
1
) AS row_num,
@current_dept := department AS dummy
FROM employees
ORDER BY department, salary DESC;七、常見錯誤與排查
1. 錯誤:序號不符合預(yù)期
- ??原因??:未正確指定
ORDER BY或PARTITION BY - ??解決??:檢查排序字段是否明確,分組條件是否合理
2. 錯誤:性能低下
- ??原因??:未使用索引導(dǎo)致全表掃描
- ??解決??:使用
EXPLAIN分析執(zhí)行計劃,添加必要索引
3. 錯誤:結(jié)果集為空
- ??原因??:外層查詢條件與子查詢中的
WHERE沖突 - ??解決??:驗(yàn)證過濾條件邏輯
八、最佳實(shí)踐
- ??明確排序規(guī)則??:始終顯式指定
ORDER BY的排序方向(ASC/DESC) - ??慎用全局排序??:避免無
PARTITION BY的大數(shù)據(jù)集操作 - ??監(jiān)控內(nèi)存使用??:窗口函數(shù)可能消耗大量臨時內(nèi)存
- ??版本驗(yàn)證??:生產(chǎn)環(huán)境確認(rèn) MySQL 版本 >= 8.0
- ??結(jié)合 CTE 使用??:提高復(fù)雜查詢的可讀性
WITH ranked_products AS (
SELECT
product_id,
ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales DESC) AS rn
FROM products
)
SELECT * FROM ranked_products WHERE rn = 1;??總結(jié)??:ROW_NUMBER() 是處理行級序號分配的利器,特別適合需要精確控制行順序的場景。合理使用可顯著簡化分頁、去重、Top N查詢等操作,但需注意其對性能的影響,尤其在處理海量數(shù)據(jù)時需結(jié)合索引優(yōu)化。
到此這篇關(guān)于MySQL 中 ROW_NUMBER() 函數(shù)詳解的文章就介紹到這了,更多相關(guān)mysql row_number()函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
玩轉(zhuǎn)?MySQL?庫表:庫和表的操作"通關(guān)指南"
文章主要介紹了MySQL數(shù)據(jù)庫的基本概念、結(jié)構(gòu)和操作方法,包括數(shù)據(jù)庫和MySQL服務(wù)端的區(qū)別,SQL語句分類,以及數(shù)據(jù)庫和表的創(chuàng)建、查看、修改和刪除等操作,最后還介紹了備份和恢復(fù)數(shù)據(jù)庫的方法2026-04-04
MYSQL中統(tǒng)計查詢結(jié)果總行數(shù)的便捷方法省去count(*)
查看手冊后發(fā)現(xiàn)SQL_CALC_FOUND_ROWS關(guān)鍵詞的作用是在查詢時統(tǒng)計滿足過濾條件后的結(jié)果的總數(shù)(不受 Limit 的限制)具體使用如下,感興趣的朋友可以學(xué)習(xí)下2013-07-07
最新MySql8.27主從復(fù)制及SpringBoot項目中的讀寫分離實(shí)戰(zhàn)教程
MySQL主從復(fù)制是一個異步的復(fù)制過程,底層是基于MySQL1數(shù)據(jù)庫自帶的二進(jìn)制日志功能,這篇文章主要介紹了最新MySql8.27主從復(fù)制及SpringBoot項目中的讀寫分離實(shí)戰(zhàn)教程,需要的朋友可以參考下2022-08-08
wampserver下mysql導(dǎo)入數(shù)據(jù)庫的步驟
這篇文章主要介紹了wampserver下mysql導(dǎo)入數(shù)據(jù)庫的步驟,需要的朋友可以參考下2016-08-08
Mysql使用存儲過程快速添加百萬數(shù)據(jù)的示例代碼
這篇文章主要介紹了Mysql使用存儲過程快速添加百萬數(shù)據(jù),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-08-08
MySQL數(shù)據(jù)庫基礎(chǔ)篇之入門基礎(chǔ)命令小結(jié)
這篇文章主要介紹了MySQL數(shù)據(jù)庫入門基礎(chǔ)命令,總結(jié)分析了mysql數(shù)據(jù)庫基本創(chuàng)建、刪除、查看、權(quán)限等相關(guān)操作技巧與注意事項,需要的朋友可以參考下2020-05-05
Win10 64位使用壓縮包安裝最新MySQL8.0.18的教程(圖文詳解)
本文通過圖文并茂的形式給大家介紹了WIN10 64位使用壓縮包安裝最新MySQL8.0.18的教程,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下2019-12-12

