首次来源:北京万联易达 2026-01-23 一面
有没有用过窗口函数(开窗函数)?正则表达式在 MySQL 查询中使用过吗?体验如何?
最后更新:2026-10-29 · 基于第 1 次作答
结论:窗口函数(ROW_NUMBER/RANK/SUM() OVER)适合报表/排名/去重取最新,MySQL 8.0+ 支持;正则(REGEXP/RLIKE)能表达复杂匹配但性能差,只适合小数据量/离线。 关键词:ROW_NUMBER · RANK · OVER PARTITION · REGEXP · 回表 边界:8.0 以下无窗口函数;大表用窗口函数会全表扫描/排序,性能差,尽量下推到应用或离线。
核心考点定位:面试官想确认你是否知道 MySQL 8.0 新增的窗口函数是"分组的进阶"——它不折叠行,每行保留并附加窗口计算值;以及你是否理解正则表达式在 MySQL 中的性能代价,别在业务主链路乱用。
机制链(≥3 环):
OVER (PARTITION BY ... ORDER BY ...) 定义窗口,对窗口内每行求 ROW_NUMBER/SUM 而不折叠行。ORDER BY 排序并维护窗口,无法走普通索引直接输出。REGEXP 无法用普通 B+Tree 索引,需要全表扫描逐行正则求值。证据锚点(去重 ≥10):
ROW_NUMBER():窗口内行号,常用于去重取最新(PARTITION BY user_id ORDER BY created_at DESC)。RANK()/DENSE_RANK():排名(跳号/不跳号),用于排行榜。SUM() OVER (PARTITION BY ...):累计/分组求和,用于占比、累计值。LAG()/LEAD():取上一行/下一行值,用于环比、同环比。NTILE():分桶。OVER (PARTITION BY ... ORDER BY ...):窗口定义,决定分组与排序。REGEXP/RLIKE:正则匹配,MySQL 8.0 用 ICU 库。REGEXP_LIKE()/REGEXP_REPLACE()/REGEXP_SUBSTR():8.0+ 函数式正则。EXPLAIN:确认是否 type=ALL 全表扫描(正则几乎必然)。对比与权衡:
| 实现 | 能力 | 性能 | 适用 |
|---|---|---|---|
| 窗口函数(8.0+) | 强(排名/累计/去重) | 中(需排序) | 报表、离线、中小表 |
| GROUP BY 聚合 | 折叠行,丢明细 | 好 | 只取汇总值 |
| 应用层 Java 处理 | 灵活 | 取决于数据量 | 需分页/流式 |
REGEXP | 复杂匹配 | 差(全表扫) | 小数据量、校验 |
LIKE '%x%' | 简单子串 | 差(无前缀索引) | 简单包含匹配 |
常见误区:
GROUP BY 一样折叠行 → 正确:窗口函数保留每一行,只附加窗口计算值 → 为什么错:混淆"聚合折叠"与"窗口逐行"。REGEXP 没问题 → 正确:正则无法走索引,大表 type=ALL 全表扫描,性能不可接受 → 为什么错:只看功能,不看执行计划。LIKE 前缀查询 → 正确:有前缀的 LIKE 'abc%' 可走索引,正则不能 → 为什么错:把正则当万能索引。适用边界:窗口函数与正则适合离线/报表/小数据量校验,不要放进业务主链路;大表排名用 Redis zset 或预聚合表,正则校验放到应用层或 CHECK 约束小表;8.0 以下无窗口函数需先确认版本。
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) rn,外层 WHERE rn=1。GROUP BY + 自连接的性能对比。RANK() 与 DENSE_RANK() 区别?RANK 跳号(1,1,3),DENSE_RANK 不跳号(1,1,2)。EXPLAIN 看 type=ALL。LIKE、全文索引、或应用层预过滤代替。【结论】 窗口函数(ROW_NUMBER/RANK/SUM() OVER)适合报表、排名、取每组最新,MySQL 8.0+ 才有;正则(REGEXP/RLIKE)能表达复杂匹配但性能差,只适合小数据量或离线。
【三点】 第一,窗口函数我用在统计报表:比如取每个用户最新一条订单、算累计占比、排名,用 ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) 加外层 WHERE rn=1,它保留每一行并附加窗口值,不像 GROUP BY 那样折叠行。第二,正则我在校验类场景用过,比如校验字段格式、提取子串(REGEXP_LIKE/REGEXP_SUBSTR),但只在数据量小、离线场景用。第三,体验上最大的教训是性能:窗口函数要排序维护窗口,正则无法走索引、几乎必然 type=ALL 全表扫描,我在早期 ERP 写大 SQL 吃过苦,数据量大后把这类逻辑下推到应用层或预聚合,不让数据库背这种成本。
【边界】 窗口函数 8.0 以下不可用(5.7 需用户变量模拟);大表排名用 Redis zset 或预聚合表,正则放应用层或小表 CHECK,别进业务主链路。
题目:有没有用过窗口函数开窗函数正则表达式在MySQL查询中使用过
难度:medium
标签:db/mysql/index, real-interview, difficulty/medium
评分:⭐⭐⭐☆☆(3/5)
练习次数:1
有用过窗口函数,也用过正则,不过基本上是在统计报表中使用的,不会在业务系统对外的功能中使用,这种东西性能差的有些离谱,一些东西可以在外部通过业务设计实现,不要把压力都抛给数据库,我之前最初的写ERP的时候喜欢写大sql,后来用户量和数据量提高后,吃了很多苦;数据量小的时候用这些东西没问题,数据量大了最好不要在数据库中用这些东西;
优点:立场正确——窗口函数/正则只用于统计报表、避免压给 DB,且有 ERP 大 SQL 的实践教训。
不足:未举具体函数(ROW_NUMBER/RANK/LAG/SUM() OVER、REGEXP_LIKE),体验偏泛,未提 8.0 版本门槛。
补充:窗口函数 8.0+、保留每行不折叠;正则无法走索引、type=ALL 全表扫描;大表排名用 zset/预聚合。
完整讲解见上方「完整讲解(权威版)」