MySQL 中 ROW_NUMBER() 函数最佳实践

2025-06-26 17:50

本文主要是介绍MySQL 中 ROW_NUMBER() 函数最佳实践,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《MySQL中ROW_NUMBER()函数最佳实践》MySQL中ROW_NUMBER()函数,作为窗口函数为每行分配唯一连续序号,区别于RANK()和DENSE_RANK(),特别适合分页、去重...

MySQL 中 ROW_NUMBER() 函数详解

ROW_NUMBER() 是 SQL 窗口函数中的一种,用于为查询结果集中的每一行分配一个​​唯一的连续序号​​。与 RANK() 和 DENSE_RANK() 不同,ROW_NUMBER() 不会处理重复值,即使排序字段值相同,也会严格按行顺序递增编号。

一、基础语法

ROW_NUMBER() OVER (
    [PARTITION BY 分组字段]
    ORDER BY 排序字段 [ASC|DESC]
)
  • ​PARTITION BY​​:按指定字段分组,每组内重新从1开始编号。
  • ​ORDER BY​​:决定排序逻辑,影响行号的分配顺序。

二、核心特点

​特性​​说明​
唯一性每行序号严格递增,不重复(即使排序字段值相同)
灵活性可结合分组(PARTITION BY)实现复杂场景
兼容性MySQL 8.0+ 原生支持,低版本需用变量模拟
性能影响未优化时可能导致全表扫描,需合理使用索引

三、典型应用场景

1. 数据分页查询

-- 查询第3页数据(每页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. 删除重复数据

-- 保留最新记录(假设 create_time 为时间戳)
DELETE FROM orders
WHERE (i编程d, 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  -- 删除重复项,保留最新一条
);

3. 分组取Top N记录

-- 获取每个部门薪资前3名
SELECT *
FROM (
    SELECT 
        name, department, salary,
        ROW_NUMBER() OVER (
            PARTITION BY department 
            ORDER BY salary DESC
        ) AS deptChina编程_rank
    FROM employees
) ranked
WHERE dept_rank <= 3;

4. 生成唯一流水号

-- 按日期生成订单流水号(格式:YYYYMMDD-0001)
SELECT 
    order_id,
    CONCAT(
        DATE_FORMAT(create_time, '%Y%m%dChina编程'), 
        '-', 
     http://www.chinasem.cn   LPAD(ROW_NUMBER() OVER (
            PARTITION BY DATE(create_time) 
            ORDER BY create_time
        ), 4, '0')
    ) AS serial_num
FROM orders;

四、与其他排序函数对比

函数重复值处理示例结果(排序字段值相同)
ROW_NUMBER()强制分配不同序号1, 2, 3, 4
RANK()相同值共享排名,后续跳过序号1, 1, 3, 4
DENSE_RANK()相同值共享排名,后续连续递增1, 1, 2, 3
-- 对比三种函数
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;

五、性能优化技巧

1. 索引设计

为 PARTITION BY 和 ORDER BY 涉及的字段创建联合索引:

CREATE INDEX idx_dept_salary ON employees(department, salary DESC);

2. 减少计算范围

-- 仅处理2023年数据
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. 避免嵌套查询

-- 优化前(性能差)
SELECT * FROM (
    SELECT *, ROW_NUMBER() OVER (...) AS rn
    FROM large_table
) t WHERE rn <= 100;
-- 优化后(直接使用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. 错误:序号不符合预期

  • ​原因​​:未正确指定 ORDER BY 或 PARTITION BY
  • ​解决​​:检查排序字段是否明确,分组条件是否合理

2. 错误:性能低下

  • ​原因​​:未使用索引导致全表扫描
  • ​解决​​:使用 EXPLAIN 分析执行计划,添加必要索引

3. 错误:结果集为空

  • ​原因​​:外层查询条件与子查询中的 WHERE 冲突
  • ​解决​​:验证过滤条件逻辑

八、最佳实践

  • ​明确排序规则​​:始终显式指定 ORDER BY 的排序方向(ASC/Dhttp://www.chinasem.cnESC)
  • ​慎用全局排序​​:避免无 PARTITION BY 的大数据集操作
  • ​监控内存使用​​:窗口函数可能消耗大量临时内存
  • ​版本验证​​:生产环境确认 MySQL 版本 >= 8.0
  • ​结合 CTE 使用​​:提高复杂查询的可读性
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;

​总结​​:ROW_NUMBER() 是处理行级序号分配的利器,特别适合需要精确控制行顺序的场景。合理使用可显著简化分页、去重、Top N查询等操作,但需注意其对性能的影响,尤其在处理海量数据时需结合索引优化。

到此这篇关于MySQL 中 ROW_NUMBER() 函数详解的文章就介绍到这了,更多相关mysql row_number()函数内容请搜索编程China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!

这篇关于MySQL 中 ROW_NUMBER() 函数最佳实践的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1155223

相关文章

C++ move 的作用详解及陷阱最佳实践

《C++move的作用详解及陷阱最佳实践》文章详细介绍了C++中的`std::move`函数的作用,包括为什么需要它、它的本质、典型使用场景、以及一些常见陷阱和最佳实践,感兴趣的朋友跟随小编一起看... 目录C++ move 的作用详解一、一句话总结二、为什么需要 move?C++98/03 的痛点⚡C++

MySQL字符串转数值的方法全解析

《MySQL字符串转数值的方法全解析》在MySQL开发中,字符串与数值的转换是高频操作,本文从隐式转换原理、显式转换方法、典型场景案例、风险防控四个维度系统梳理,助您精准掌握这一核心技能,需要的朋友可... 目录一、隐式转换:自动但需警惕的&ld编程quo;双刃剑”二、显式转换:三大核心方法详解三、典型场景

MySQL中between and的基本用法、范围查询示例详解

《MySQL中betweenand的基本用法、范围查询示例详解》BETWEENAND操作符在MySQL中用于选择在两个值之间的数据,包括边界值,它支持数值和日期类型,示例展示了如何使用BETWEEN... 目录一、between and语法二、使用示例2.1、betwphpeen and数值查询2.2、be

MySQL快速复制一张表的四种核心方法(包括表结构和数据)

《MySQL快速复制一张表的四种核心方法(包括表结构和数据)》本文详细介绍了四种复制MySQL表(结构+数据)的方法,并对每种方法进行了对比分析,适用于不同场景和数据量的复制需求,特别是针对超大表(1... 目录一、mysql 复制表(结构+数据)的 4 种核心方法(面试结构化回答)方法 1:CREATE

SQL Server中行转列方法详细讲解

《SQLServer中行转列方法详细讲解》SQL行转列、列转行可以帮助我们更方便地处理数据,生成需要的报表和结果集,:本文主要介绍SQLServer中行转列方法的相关资料,需要的朋友可以参考下... 目录前言一、为什么需要行转列二、行转列的基本概念三、使用PIVOT运算符进行行转列1.创建示例数据表并插入数

MySQL MHA集群详解(数据库高可用)

《MySQLMHA集群详解(数据库高可用)》MHA(MasterHighAvailability)是开源MySQL高可用管理工具,用于自动故障检测与转移,支持异步或半同步复制的MySQL主从架构,本... 目录mysql 高可用方案:MHA 详解与实战1. MHA 简介2. MHA 的组件组成(1)MHA

SQL 注入攻击(SQL Injection)原理、利用方式与防御策略深度解析

《SQL注入攻击(SQLInjection)原理、利用方式与防御策略深度解析》本文将从SQL注入的基本原理、攻击方式、常见利用手法,到企业级防御方案进行全面讲解,以帮助开发者和安全人员更系统地理解... 目录一、前言二、SQL 注入攻击的基本概念三、SQL 注入常见类型分析1. 基于错误回显的注入(Erro

MySQL基本表查询操作汇总之单表查询+多表操作大全

《MySQL基本表查询操作汇总之单表查询+多表操作大全》本文全面介绍了MySQL单表查询与多表操作的关键技术,包括基本语法、高级查询、表别名使用、多表连接及子查询等,并提供了丰富的实例,感兴趣的朋友跟... 目录一、单表查询整合(一)通用模版展示(二)举例说明(三)注意事项(四)Mapper简单举例简单查询

pandas使用apply函数给表格同时添加多列

《pandas使用apply函数给表格同时添加多列》本文介绍了利用Pandas的apply函数在DataFrame中同时添加多列,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录一、Pandas使用apply函数给表格同时添加多列二、应用示例一、Pandas使用apply函

MySQL中的DELETE删除数据及注意事项

《MySQL中的DELETE删除数据及注意事项》MySQL的DELETE语句是数据库操作中不可或缺的一部分,通过合理使用索引、批量删除、避免全表删除、使用TRUNCATE、使用ORDERBY和LIMI... 目录1. 基本语法单表删除2. 高级用法使用子查询删除删除多表3. 性能优化策略使用索引批量删除避免