首页/新闻资讯/正文详情

SQL窗口函数速查:OVER()、排名与窗口帧避坑

发布时间:2026/11/4 23:19:52 来源:云帆数科 栏目:资讯中心
SQL窗口函数速查:OVER()、排名与窗口帧避坑
简介《SQL窗口函数速查表》PDF面向数据库管理员、数据分析师、数据科学家与开发人员聚焦窗口函数概念零散、语法与适用边界易混的问题适合具备基础SQL、希望提升复杂查询与报表分析能力的中级读者。整份资源仅含1个PDF文件压缩包约841KB轻量易存便于随查随用文档按排名、行序号、聚合三类函数组织系统梳理ROW_NUMBER、RANK、DENSE_RANK、LEAD、LAG及SUM、AVG、COUNT等用法并给出OVER、PARTITION BY、ORDER BY、frame_clause的语法结构与参数说明。每个函数配合示例代码与返回结果帮助读者理解分组排序、前后行取值、累计与滑动窗口计算等典型场景也能为报表生成、异常值排查和教学讲解提供直接参考。目前已有255人学习下载适合作为案头速查与面试复习材料。1. 一行 GROUP BY 交不出的报表才是窗口函数的主场月度复盘会上业务方要一张表每笔订单的明细、它所在大区的累计成交额、它在本大区按金额的排名、以及和上一笔的时间间隔。用 GROUP BY 一聚合明细就没了用自连接硬拼SQL 三层嵌套还慢得离谱。这类“既要明细又要汇总”的查询正是 SQL 窗口函数的主场——它在一组行上做聚合却把每一行原样留下。这份《SQL窗口函数速查表.pdf》把日常写报表时最高频的函数、OVER() 的三段结构、帧子句的边界写法压缩成一份可以边写边翻的对照表适合天天写查询的分析师、要优化慢报表的后端开发以及被面试题问住想系统补一遍 sql 的人。它不教你数据库原理只解决一件事下次遇到排名、累计、环比、去重取最新能直接翻到那一页照抄。2. OVER() 骨架拆解PARTITION BY、ORDER BY、FRAME 三段怎么切窗口函数之所以让很多人写得心虚是因为它把“分组、排序、取范围”三件事塞进了一个 OVER() 里任何一段写错结果都不会报错只会静默地算出另一组数。速查表把这三段拆开列实际动手时按这个顺序对齐八成的问题在写之前就能避开。2.1 聚合函数和窗口函数的差别明细为什么没被折叠GROUP BY 的本质是“把多行压成一行”压缩之后原始行的身份就丢了。窗口函数不压缩它给每一行挂一个“基于它所属那组算出来的值”。两者的差别不是语法糖而是结果集的行数模型不同。-- 聚合写法一个分区只剩一行明细消失 SELECT region, SUM(amount) AS region_total FROM sales GROUP BY region; -- 窗口写法行数不变每行后面挂一个分区汇总 SELECT region, sale_date, amount, SUM(amount) OVER (PARTITION BY region) AS region_total FROM sales;第一段查询返回两行两个大区第二段返回六行每行都带着自己所属大区的总额。逻辑说明SUM(amount) OVER (PARTITION BY region)里的 SUM 仍然是求和但 OVER 告诉引擎“别把这组压成一行算完把结果贴回每一行”。参数说明PARTITION BY region是切分依据等价于 GROUP BY 的分组列但不会减少行数省略 PARTITION BY 时整个结果集就是一个窗口所有行共用一个汇总值。这里有个容易忽略的边界窗口函数在逻辑执行顺序上位于 GROUP BY 和 HAVING 之后、ORDER BY 之前。也就是说如果整条 SQL 里同时有 GROUP BY 和窗口函数窗口函数看到的是聚合之后的结果集。想要“先聚合再窗口”就把聚合写进子查询想要“先窗口再聚合”得反过来包一层。分不清这一点就会写出SUM(SUM(amount)) OVER ()这种看着别扭但语法合法的嵌套速查表里专门标了这一类组合写法。提示窗口函数不能写在 WHERE 里也不能直接用它产生的列别名做过滤条件原因是 WHERE 的执行时机早于窗口计算。这条在后面第 5 章会展开。2.2 三段式的执行顺序先切分、再排序、最后取帧OVER() 内部三段的语义是层层收窄的PARTITION BY 决定“和谁一起算”ORDER BY 决定“在组内按什么顺序算”FRAME 决定“算的时候取哪一段行”。三段都省略时整个结果集是一个窗口且没有排序聚合范围是全量。SUM(amount) OVER ( PARTITION BY region -- 1. 切分区每个 region 独立成一个窗口 ORDER BY sale_date -- 2. 组内排序定义当前行的位置 ROWS BETWEEN UNBOUNDED PRECEDING -- 3. 取帧从分区第一行 AND CURRENT ROW -- 到当前行累计 ) AS running_total参数说明UNBOUNDED PRECEDING表示分区起点CURRENT ROW表示当前行n PRECEDING/n FOLLOWING表示往前/往后 n 行UNBOUNDED FOLLOWING表示分区终点。这一串写全之后语义是“截至当前行的累计和”等价于财务报表里的滚动合计。关键在于第二段。ORDER BY 一旦写进去它不仅决定顺序还隐式决定了一个默认帧。很多人以为“我只写了 ORDER BY没写帧那应该还是全量吧”实际默认帧是RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW也就是累计。这个默认值造成的“数值每行都不一样”是窗口函数最经典的翻车现场第 4 章会拿两组对照数据把它彻底说清。第三段的写法还受引擎约束帧边界的起点不能晚于终点BETWEEN 2 FOLLOWING AND 1 PRECEDING会直接报错某些引擎在 RANGE 模式下只接受数值或时间类型的边界写RANGE BETWEEN 2024-01-01 PRECEDING这种字符串是非法的。写之前先确认自己用的是 ROWS按行数还是 RANGE按排序键的值两者在排序键有重复值时会给出不同结果。2.3 建一张最小可复现的表把三段拆开跑空谈结构不如直接跑一遍。下面这张表只有两个分区、六行数据足够验证绝大多数窗口行为。CREATE TABLE sales ( region VARCHAR(8), -- 大区代号 sale_date DATE, -- 成交日期 amount DECIMAL(12,2) -- 成交金额 ); INSERT INTO sales (region, sale_date, amount) VALUES (R01, 2024-01-05, 1200.00), (R01, 2024-01-19, 800.00), (R01, 2024-02-02, 1500.00), (R02, 2024-01-08, 900.00), (R02, 2024-01-22, 900.00), (R02, 2024-02-11, 2100.00);数据里特意让 R02 出现两个 900.00是为了后面看排名函数的并列行为和 RANGE 帧的 peer 行效应。接下来把三种窗口写法并排跑一次性看清“全量”“累计”“按行滑动”的区别。SELECT region, sale_date, amount, -- 不写 ORDER BY整分区求和三行值相同 SUM(amount) OVER (PARTITION BY region) AS region_total, -- 只写 ORDER BY默认帧是累计值逐行变大 SUM(amount) OVER (PARTITION BY region ORDER BY sale_date) AS running_total, -- 显式写 ROWS 帧当前行及前一行窗口大小为 2 SUM(amount) OVER (PARTITION BY region ORDER BY sale_date ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS last2_sum FROM sales ORDER BY region, sale_date;以 R01 为例三列的结果分别是region_total三行都是 3500.00running_total依次是 1200.00、2000.00、3500.00last2_sum依次是 1200.00、2000.00、2300.00。第一行没有前一行1 PRECEDING在分区边界处自动截断不会补 NULL 也不会报错这个截断行为是标准规定的可以放心依赖。跑完这组对照再回头看速查表里的语法页三段各自的效果就有了具体数字锚点。后续换任何函数AVG、COUNT、MAX只要 OVER() 这三段不变窗口范围就完全一致——这也是窗口函数比自连接好维护的地方换指标不用重写连接条件。3. 排名与偏移ROW_NUMBER、RANK、DENSE_RANK 和 LEAD/LAG 的选型边界速查表把函数按用途分成排名、行偏移、聚合三类这个分法比按字母序排更贴合实际使用。真正需要判断的只有两件事并列时该跳号还是不该跳号以及偏移函数在分区边界上返回什么。3.1 三个排名函数并列时到底跳不跳号ROW_NUMBER、RANK、DENSE_RANK 的差别只在“遇到相同排序键时怎么办”这一个点上但选错会让下游的筛选条件直接失效。函数并列行的取值下一名取值结果是否连续典型用途ROW_NUMBER()各不相同的连续序号顺延连续去重取最新、分页RANK()相同跳过占用的名次不连续榜单、竞赛名次DENSE_RANK()相同不跳过连续分级、档次划分SELECT region, amount, ROW_NUMBER() OVER (PARTITION BY region ORDER BY amount DESC) AS rn, RANK() OVER (PARTITION BY region ORDER BY amount DESC) AS rk, DENSE_RANK() OVER (PARTITION BY region ORDER BY amount DESC) AS drk FROM sales ORDER BY region, amount DESC;在 R02 分区里2100.00 排第一两个 900.00 并列ROW_NUMBER 给出 1、2、3RANK 给出 1、2、2DENSE_RANK 给出 1、2、2。注意 RANK 和 DENSE_RANK 在只有两档数据时看不出区别把 R02 换成 2100、900、900、600 就能看到 RANK 是 1、2、2、4DENSE_RANK 是 1、2、2、3。选型理由很直接如果下游要WHERE rk 3取前三名用 RANK 可能返回四行甚至更多并列把名额撑开用 DENSE_RANK 返回的是“三个档次”用 ROW_NUMBER 则一定是三行但并列行的取舍由引擎决定。做“每户取最新一条”这种必须精确一行的场景ROW_NUMBER 是唯一正确选择因为另外两个都会在并列时返回多行导致下游数据翻倍。速查表在每个排名函数下面都标了返回行数特征就是防这个。还有一个隐藏参数ORDER BY amount DESC NULLS LAST。不同引擎对 NULL 的默认排序位置不一致有的排最前有的排最后排名结果会整体错位。涉及可能为空的排序键时把 NULLS FIRST / NULLS LAST 显式写出来别赌默认值。3.2 去重取最新一条ROW_NUMBER 必须包一层子查询这是窗口函数最高频的实战用法也是新手最容易写错的地方——试图在 WHERE 里直接过滤rn 1。-- 错误写法WHERE 里引用窗口列执行顺序上根本拿不到 SELECT region, sale_date, amount, ROW_NUMBER() OVER (PARTITION BY region ORDER BY sale_date DESC) AS rn FROM sales WHERE rn 1; -- 报错或语义错误 -- 正确写法子查询或 CTE先算出序号外层再过滤 WITH ranked AS ( SELECT region, sale_date, amount, ROW_NUMBER() OVER (PARTITION BY region ORDER BY sale_date DESC, amount DESC) AS rn FROM sales ) SELECT region, sale_date, amount FROM ranked WHERE rn 1;逻辑说明内层把每个大区的行按日期倒序编号最新一条拿到 rn 1外层只保留 rn 1 的行每个大区恰好一行。参数说明ORDER BY sale_date DESC决定“最新”的定义后面补的amount DESC是 tiebreaker——如果同一个大区同一天有两笔成交只按日期排序时 rn 1 花落谁家由引擎的物理读取顺序决定今天跑是这个结果明天统计信息更新后可能换一条。这类不确定性在没有主键兜底的表上尤其常见加一个唯一性足够的列做次级排序结果才可复现。如果表里有自增主键或订单号最稳的写法是ORDER BY sale_date DESC, id DESC。这一步多写五个字符能省掉后面反复对数对不上的半小时。3.3 LEAD / LAGoffset、default 与时间差计算偏移函数取的是“当前行往前/往后第 n 行”的值两个参数值得记牢第二个参数是偏移量默认 1第三个参数是越界时的默认值默认 NULL。SELECT region, sale_date, amount, LAG(amount, 1, 0) OVER (PARTITION BY region ORDER BY sale_date) AS prev_amount, LEAD(amount, 1, 0) OVER (PARTITION BY region ORDER BY sale_date) AS next_amount, amount - LAG(amount) OVER (PARTITION BY region ORDER BY sale_date) AS diff_prev FROM sales ORDER BY region, sale_date;LAG(amount, 1, 0)表示取前一行金额分区第一行没有前行时返回 0 而不是 NULLLAG(amount)用的是默认偏移和默认 NULL算差值时第一行会得到 NULL后续聚合比如 AVG会自动忽略 NULL两种写法的统计口径并不相同。做环比、同比这类需要“第一期没有基数”的指标时用 NULL 更诚实用 0 会把第一期算成百分之百增长这是报表口径上的实质差异不是风格问题。把 LAG 和累计求和组合起来可以做出会话切分gap-and-islands这类稍复杂的分析先用 LAG 算出相邻事件的时间间隔标记超过阈值的行为“新会话起点”再用累计求和给每行打上会话编号。WITH step1 AS ( SELECT user_id, event_time, LAG(event_time) OVER (PARTITION BY user_id ORDER BY event_time) AS prev_time FROM user_events ), step2 AS ( SELECT user_id, event_time, CASE WHEN prev_time IS NULL OR event_time prev_time INTERVAL 30 MINUTE THEN 1 ELSE 0 END AS is_new_session FROM step1 ) SELECT user_id, event_time, SUM(is_new_session) OVER (PARTITION BY user_id ORDER BY event_time ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS session_id FROM step2;逻辑说明第一步用 LAG 拿到上一条事件时间第二步判断间隔是否超过 30 分钟首条事件prev_time IS NULL也判为新会话第三步对标记做累计求和同一会话内的行会拿到相同的 session_id。参数说明INTERVAL 30 MINUTE是标准写法部分引擎需要用时间加减函数替代累计求和那一步必须显式写ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW虽然默认帧在这里恰好等价但显式写出来可以避免以后有人改了 ORDER BY 键之后语义悄悄漂移。4. 窗口帧 FRAME默认帧的坑和滑动窗口的正确写法帧子句是窗口函数里最容易被跳过的一段也是结果最容易“看着像对的、其实全错”的一段。速查表把 ROWS、RANGE、GROUPS 三种模式并列列出实际工作中前两种覆盖了绝大多数场景。4.1 有 ORDER BY 和没 ORDER BY默认帧完全不同这条差异值得单独拿出来说因为它不报错、不告警只是数不对。-- 写法 A没有 ORDER BY默认帧是整个分区 SELECT region, sale_date, amount, SUM(amount) OVER (PARTITION BY region) AS total_a FROM sales; -- 写法 B加了 ORDER BY默认帧变成起点到当前行 SELECT region, sale_date, amount, SUM(amount) OVER (PARTITION BY region ORDER BY sale_date) AS total_b FROM sales;写法 A 每个分区的三行拿到同一个值R01 全是 3500.00写法 B 拿到的是 1200.00、2000.00、3500.00。两段 SQL 只差一个 ORDER BY语义从“分区总额”变成了“滚动累计”。很多人排查半天以为自己写错了 SUM实际上是默认帧在起作用。提示要“分区总额 分区内排序”同时存在正确写法是SUM(amount) OVER (PARTITION BY region)单独算总额ROW_NUMBER() OVER (PARTITION BY region ORDER BY sale_date)单独算序号两个窗口互不影响。不要试图在一个 OVER 里既排序又要全量合计。再看 RANGE 模式下的 peer 行效应。R02 分区有两个 900.00排序键如果是 amountRANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW会把所有取值相同的行一起算进当前帧两个 900.00 拿到相同的累计值换成ROWS模式则严格按行号切第二个 900.00 会把第一个也算进去。同样是“累计”两种模式的数字不一样选哪个取决于业务语义按值累计同额同待遇用 RANGE按行累计逐笔流水用 ROWS。4.2 ROWS BETWEEN累计、移动平均和同期对比ROWS 模式最直观边界就是行数。三种常用形态各自对应一类报表需求。SELECT region, sale_date, amount, -- 1. 累计分区起点到当前行 SUM(amount) OVER (PARTITION BY region ORDER BY sale_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total, -- 2. 近 3 笔移动平均当前行及前 2 行 AVG(amount) OVER (PARTITION BY region ORDER BY sale_date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS ma_3, -- 3. 前后各 1 行的居中窗口用于平滑或找局部峰值 AVG(amount) OVER (PARTITION BY region ORDER BY sale_date ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS centered_avg FROM sales ORDER BY region, sale_date;逻辑说明第 1 种是标准累计第 2 种窗口大小固定为 3 行不足 3 行时按实际行数计算分区前两行的平均是基于 1 行和 2 行算的不会补 NULL第 3 种以当前行为中心常用于时间序列平滑。参数说明n PRECEDING和n FOLLOWING的 n 必须是常数或参数不能是列引用——想按每行不同的窗口宽度计算标准 SQL 不支持需要用自连接或条件聚合绕开。移动平均这里有个业务口径问题窗口大小固定为 3 行意味着数据有缺失日期时“近 3 笔”可能跨越很长的时间跨度。要做“近 30 天”这种按时间定义的窗口得换成 RANGE 模式。4.3 RANGE 和 GROUPS按值分组而不是按行RANGE 的边界是排序键的值适合时间窗口GROUPS 的边界是“排序键的取值分组数”用得少但确实存在。-- RANGE 时间间隔近 30 天窗口要求排序键是日期类型 SELECT region, sale_date, amount, SUM(amount) OVER (PARTITION BY region ORDER BY sale_date RANGE BETWEEN INTERVAL 30 DAY PRECEDING AND CURRENT ROW) AS sum_30d FROM sales ORDER BY region, sale_date;参数说明INTERVAL 30 DAY PRECEDING表示“当前行日期减 30 天”作为窗口起点凡是日期落在这个区间内的行都参与求和。这种写法在各引擎的支持程度不一有的只支持数值型边界写RANGE BETWEEN 30 PRECEDING此时排序键必须是数值日期间隔需要先转成天数差有的要求排序键唯一或者至少有序。跑之前先确认自己环境的支持范围别直接照搬。EXCLUDE子句是较新标准才补齐的能力用来把当前行从帧里剔掉做“不含本行的均值”这类对比很方便SELECT region, sale_date, amount, AVG(amount) OVER (PARTITION BY region ORDER BY sale_date ROWS BETWEEN 3 PRECEDING AND 3 FOLLOWING EXCLUDE CURRENT ROW) AS avg_without_self FROM sales;这个特性在老版本上会直接语法报错速查表在对应函数旁标注了适用版本范围。遇到不支持的引擎等价写法是把当前行权重扣掉(SUM(...) - amount) / (COUNT(...) - 1)麻烦但通用。5. 避坑与排查窗口函数写错的五条血泪记录窗口函数的麻烦在于它几乎不报错。语法通过、结果返回、行数正确但数字可能是错的而且错得很像对的。下面五条是我在实际对数中真踩过的每条按“现象 → 原因 → 解决”记。5.1 五个高频翻车现场第一条WHERE 里过滤窗口列报“列不存在”。现象写好ROW_NUMBER() OVER (...) AS rn外层直接WHERE rn 1引擎提示 rn 这个列不存在。原因逻辑执行顺序是 FROM → WHERE → GROUP BY → HAVING → 窗口计算 → SELECT → ORDER BYWHERE 执行时窗口列还没算出来。解决用 CTE 或派生表包一层外层再过滤部分数据仓库类引擎支持 QUALIFY 子句可以把窗口条件直接写在 QUALIFY 里语义上等价于“窗口计算之后过滤”。第二条加了 ORDER BY 忘了写帧累计值悄悄替换了总额。现象本来要每行显示大区总额结果第一行 1200、第二行 2000、第三行 3500逐行递增。原因ORDER BY 一旦出现默认帧变成RANGE UNBOUNDED PRECEDING AND CURRENT ROW。解决要全量就删掉 OVER 里的 ORDER BY或者显式写ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING。后者读起来啰嗦但意图明确团队协作时更不容易被后人改错。第三条用 RANK 取前三结果返回了五行。现象WHERE rk 3本该三行实际返回四到五行。原因RANK 遇到并列会跳号两个第 2 名之后直接是第 4 名但如果并列发生在第 3 名就会出现多个 3。解决要精确行数用 ROW_NUMBER要按档次取用 DENSE_RANK业务上确实允许并列时用 RANK 并在需求文档里写清楚“可能多于 N 行”。第四条同一个查询跑两次取到的“最新一条”不一样。现象去重取最新的结果每次刷新都变对数时被业务方追着问。原因ORDER BY 的排序键不唯一比如只按日期排同一天有多笔并列行的先后由执行计划决定走索引扫描和走全表扫描可能给出不同顺序。解决排序键补一个唯一性足够的列通常是主键或订单号写成ORDER BY sale_date DESC, id DESC。这是我个人认为性价比最高的一条习惯。第五条分区键和排序键搞反排名全乱。现象想算“每个大区内部的排名”结果排名是全局的。原因把PARTITION BY region写成了ORDER BY region或者顺序颠倒。解决写完 OVER 之后回读一遍——PARTITION BY 后面跟的是“分组维度”ORDER BY 后面跟的是“组内排序维度”两者语义完全不同写反了不报错但结果差一个量级。5.2 窗口结果要过滤三条改写路径怎么选除了 QUALIFY通用的改写方式就三种选哪种取决于引擎和可读性。-- 路径一CTE可读性最好适合复杂查询 WITH ranked AS ( SELECT region, sale_date, amount, ROW_NUMBER() OVER (PARTITION BY region ORDER BY sale_date DESC, amount DESC) AS rn FROM sales ) SELECT * FROM ranked WHERE rn 2; -- 路径二派生表适合一次性小查询不用起名字 SELECT region, sale_date, amount FROM ( SELECT region, sale_date, amount, ROW_NUMBER() OVER (PARTITION BY region ORDER BY sale_date DESC, amount DESC) AS rn FROM sales ) t WHERE rn 2; -- 路径三QUALIFY部分数据仓库类引擎支持少一层嵌套 SELECT region, sale_date, amount FROM sales QUALIFY ROW_NUMBER() OVER (PARTITION BY region ORDER BY sale_date DESC, amount DESC) 2;三种写法的执行结果一致差别在可移植性和可读性。路径一在几乎所有支持 CTE 的引擎上都能跑嵌套层次清楚适合进代码库路径二适合临时排查路径三最简洁但换引擎就可能不认。团队里如果混用多种数据库统一走路径一别为了少写两行给自己挖坑。还有个容易忽略的排查手段把窗口函数单独跑一遍不加任何外层过滤肉眼检查 rn、rk 这些序号列是不是从 1 开始连续、有没有重复、分区边界对不对。序号列异常八成是 PARTITION BY 或 ORDER BY 的问题序号正常但数值不对问题就在帧子句。按这个顺序二分比盯着整条 SQL 猜要快得多。6. 把速查表用成生产力命名窗口和一次 EXPLAIN 验证速查表翻熟之后真正能提速的是两个动作把重复的 OVER 抽成命名窗口以及上线前看一眼执行计划。6.1 WINDOW 子句重复的 OVER 抽出来一条报表 SQL 里经常有四五个指标共用同一个分区和排序每个都写一遍PARTITION BY region ORDER BY sale_date既长又容易写岔。SELECT region, sale_date, amount, SUM(amount) OVER w AS running_total, AVG(amount) OVER w AS running_avg, COUNT(*) OVER w AS running_cnt, -- 命名窗口后面可以追加 ORDER BY覆盖原来的排序 RANK() OVER (w ORDER BY amount DESC) AS amount_rank FROM sales WINDOW w AS (PARTITION BY region ORDER BY sale_date) ORDER BY region, sale_date;逻辑说明WINDOW w AS (...)定义了一个可复用的窗口后面所有OVER w都引用同一份定义改分区键时只需要改一处。参数说明命名窗口只能“追加”ORDER BY不能覆盖 PARTITION BY——OVER (w PARTITION BY xxx)是非法写法。这个限制意味着命名窗口适合“同一分区、多种排序或多种函数”的场景分区维度不同的指标还是得各写各的。6.2 验证看排序次数别只看耗时窗口函数的性能瓶颈基本都在排序上。PARTITION BY 和 ORDER BY 的组合如果和已有索引顺序一致引擎可以复用同一次排序不一致就要额外排一遍数据量大时这一下就是几秒的差距。EXPLAIN SELECT region, sale_date, amount, SUM(amount) OVER (PARTITION BY region ORDER BY sale_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS running_total FROM sales WHERE sale_date 2024-01-01;看执行计划时关注两点窗口节点下面挂了几次排序以及排序键是否和索引列顺序匹配。如果一条 SQL 里有多个窗口、排序键各不相同排序次数会成倍增加。常见的优化手段是把多个指标的排序键统一比如都按 sale_date或者建一个(region, sale_date)的复合索引让排序直接消失。验证方法也很朴素把数据量按十倍递增各跑一次记录耗时曲线。如果耗时随数据量线性增长说明排序被索引兜住了如果出现明显跳变多半是排序落到了临时空间这时候要么加索引要么把大查询拆成“先聚合到中间表、再在中间表上开窗”两段。我现在的习惯是任何带窗口函数的报表 SQL 进代码库之前必须跑一次 EXPLAIN确认排序次数没超过窗口个数并且排序键都有索引覆盖。这个动作花不了一分钟但拦下过好几次“开发环境几万行跑得飞快、生产环境几千万行直接超时”的事故。速查表负责让我写对EXPLAIN 负责让我确认它真的对——两件事都做完才算把这份 PDF 用到位。希望帮到你。本文还有配套的精品资源点击获取

相关推荐

PostgreSQL主从流复制+pgpool高可用实战指南
PostgreSQL主从流复制+pgpool高可用实战指南

简介:本资源是一份面向数据库运维工程师与PostgreSQL高可用架构实践者的完整技术方案文档,聚焦Postgres主从流复制与pgpool-II协同构建生产级高可用数据库集群。内容系统覆盖流复制原理(WAL日志实时同步、同步/异步模式对比)、pgp… · 2026/11/4 23:18:44

机器学习算法优化与硬件协同设计的效率革命
机器学习算法优化与硬件协同设计的效率革命

1. 机器学习效率革命的背后推手在波士顿查尔斯河畔的那栋标志性玻璃建筑里,一群穿着连帽衫的研究人员正用数学公式重新定义人工智能的边界。他们最近发表在NeurIPS上的论文显示,通过改进传统反向传播算法,模型训练时间缩短了40%——这相当于每… · 2026/11/4 23:18:44

Redis SCAN命令原理与华为云优化实践
Redis SCAN命令原理与华为云优化实践

1. Redis SCAN命令基础解析Redis的SCAN命令是遍历大量键值对时的高效解决方案,它通过游标式迭代避免了KEYS命令可能引发的服务阻塞问题。在华为云Redis环境中,这个命令的工作机制与开源版本保持兼容,但在底层实现上针对云环境做了优化。1.1 S… · 2026/11/4 23:17:38

智算集群性能诊断实战:Benchmark、监控与故障排查体系
智算集群性能诊断实战:Benchmark、监控与故障排查体系

1. 从一次训练任务卡死说起:智算集群为什么需要"听诊器"凌晨两点,训练任务突然卡在某个 step 不动了。日志没有报错,GPU 利用率从 95% 掉到 3%,nvidia-smi 显示显存还占着,但计算单元几乎空转。这种场景做 A… · 2026/11/4 23:56:28

AI工程化落地:从工业质检到大模型托管平台
AI工程化落地:从工业质检到大模型托管平台

1. 这次两个消息放在一起,其实是同一件事的两面先说结论:西门子与宝洁扩大AI质检合作,和Kimi K3接入AWS Bedrock,表面上一个在讲工业制造,一个在讲大模型生态,看起来风马牛不相及。但把这两条放在同一天的A… · 2026/11/4 23:56:28

MySQL函数实战:提升数据库操作效率的20个技巧
MySQL函数实战:提升数据库操作效率的20个技巧

1. MySQL函数概述与使用场景MySQL作为最流行的关系型数据库之一,其内置函数库是数据处理的核心工具集。这些函数可以大致分为日期时间、字符串处理、数学计算、系统信息等几大类,几乎覆盖了日常开发中的所有数据处理需求。在实际项目中,我经常… · 2026/11/4 23:56:28

Maven下载安装与settings.xml配置:JDK、本地仓库、镜像避坑
Maven下载安装与settings.xml配置:JDK、本地仓库、镜像避坑

1. 先把 Maven 这件事说清楚:它到底解决什么问题聊 Maven 下载安装之前,我想先花点篇幅把“这东西是干嘛的”讲透。因为我在带新人的时候发现一个很普遍的现象:很多人装 Maven 装得挺顺,mvn -v也能出结果,但对着一堆po… · 2026/11/4 23:56:28

电商数据处理自动化:流批一体与智能管道的实践
电商数据处理自动化:流批一体与智能管道的实践

1. 电商数据处理的现状与挑战电商行业经过近十年的高速发展,已经积累了海量的用户行为数据、交易数据和商品数据。根据我过去参与的几个大型电商平台数据中台建设的经验,目前主流电商平台日均产生的数据量普遍在TB级别,大促期间甚至可以达到P… · 2026/11/4 23:56:28

智能可观测性平台:从数据孤岛到自动化运维
智能可观测性平台:从数据孤岛到自动化运维

1. 项目背景与行业痛点去年某次深夜告警让我记忆犹新:某核心业务系统突发性能劣化,运维团队花了3小时才定位到是某个第三方API的异常返回触发了业务逻辑的死循环。这种传统运维的被动响应模式,正是当下企业数字化转型中面临的典型困境。随着微… · 2026/11/4 23:55:21

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38

AI辅助技术栈评估:提升研发决策效率60%
AI辅助技术栈评估:提升研发决策效率60%

1. 项目背景与核心价值技术决策一直是研发团队面临的重大挑战。随着技术生态的快速演进,技术栈的选择、维护和迭代变得愈发复杂。我们团队在过去两年里,先后经历了三次重大技术栈迁移,每次都需要投入大量人力进行技术评估和风险分析。直到去年… · 2026/11/4 0:00:17

从生成Token到直接决策:Jev如何重塑AI Agent工程实践
从生成Token到直接决策:Jev如何重塑AI Agent工程实践

1. 从"生成文字"到"拍板决策":Jev 到底在解决什么问题大多数人第一次接触大模型,脑子里建立的模型是"输入问题、输出文字"。你问它今天天气怎么样,它给你一段描述;你让它写个周报,它给你… · 2026/11/4 0:00:17

32G统一内存跑大模型:内存账、TPS实测与端云分流
32G统一内存跑大模型:内存账、TPS实测与端云分流

想在一台 32G 统一内存的小主机上把大模型跑成"日常可用",这件事我前后折腾了小半年。标题里说的这台 Mac mini M6,是我们这次讨论的目标平台,具体到手规格以实物为准;但下面这套推算方法和实测思路,对任何统… · 2026/11/4 0:00:17

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 3:16:49

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 6:59:29

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/4 7:02:38

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码