ROW_NUMBER()窗口函数使用的过程需要注意的问题及解决方法

示例sql:

          ROW_NUMBER() OVER (PARTITION BY CASE WHEN BGQYSJZBH IS NULL THEN A.BH ELSE BGQYSJZBH END ORDER BY CZSJ DESC) AS rn

 1:PARTITION BY 逻辑错误

PARTITION BY 的分组逻辑不明确,可能会导致分区数量过多或过少,从而影响行号的生成。

示例代码:

  ROW_NUMBER() OVER (PARTITION BY CASE WHEN BGQYSJZBH IS NULL THEN A.BH ELSE BGQYSJZBH END ORDER BY CZSJ DESC) AS rn

潜在问题:

  • CASE 逻辑中 BGQYSJZBH IS NULL 可能有多种分支,如果 BGQYSJZBHA.BH 有大量的唯一值,则可能导致每一行的分区都不一样,从而使得 rn 总是 1。
  • 分区过多:如果 PARTITION BY 使用的字段具有高基数(High Cardinality)(例如主键、唯一值等),则每一行都可能被认为是一个独立的分区,从而使得行号始终为 1

如何发现?

  • 如果 rn 总是 1,这通常意味着 PARTITION BY 的逻辑可能有误。

解决方案:

  1. 优化分区逻辑:确保 PARTITION BY 的字段数量不超过所需的最小分组范围。
  2. 简化逻辑:如果 BGQYSJZBH 是主键或唯一键,考虑直接使用 A.BH,而不依赖 CASE WHEN

修正版:

ROW_NUMBER() OVER (PARTITION BY NVL(BGQYSJZBH, A.BH) ORDER BY CZSJ DESC) AS rn

 

2:ORDER BY 逻辑不清晰

ORDER BY 字段不明确,导致窗口函数的排序逻辑出错,甚至出现不稳定的排序

常见的症状:

  • 排序字段 CZSJ 不唯一,导致同一分区内的行号不稳定
  • CZSJ 存在相同时间戳时,窗口函数的结果是不确定的

如何发现?

  • 如果同一分区内的 rn 行号不稳定,多次运行的结果不同。

解决方案:

  1. 确保排序字段的唯一性:在 ORDER BY 中添加一个唯一的次要排序字段(如主键或唯一ID)。
  2. 避免模糊的 ORDER BY:如果 CZSJ 可能重复,请在 ORDER BY 中添加唯一标识符。
ROW_NUMBER() OVER (PARTITION BY NVL(BGQYSJZBH, A.BH) ORDER BY CZSJ DESC, A.ID) AS rn

 

3:WHERE窗口函数 冲突

WHERE 子句中直接使用 ROW_NUMBER() 结果进行过滤,但是窗口函数是先于 WHERE 执行的,这导致WHERE 语句不起作用

示例代码:


    SELECT A.*, ROW_NUMBER() OVER (PARTITION BY NVL(BGQYSJZBH, A.BH) ORDER BY CZSJ DESC) AS rn
    FROM my_table A WHERE rn = 1

解决方案:

  1. 子查询法:在窗口函数的结果上再套一层子查询,确保WHERE是针对窗口函数的结果。
  2. 使用 CTE:通过 WITH 子句将窗口函数的结果存储为临时表,然后对该临时表进行过滤。

修正版:

WITH cte AS (
    SELECT A.*, ROW_NUMBER() OVER (PARTITION BY NVL(BGQYSJZBH, A.BH) ORDER BY CZSJ DESC) AS rn
    FROM my_table A
)
SELECT * 
FROM cte 
WHERE rn = 1;

4:性能问题(大数据集上的效率低下)

当表非常大(如百万级或千万级行数)时,窗口函数的性能变得非常低

常见的症状:

  • SQL 查询耗时过长,甚至无法在合理时间内完成
  • CPU 使用率过高,消耗大量内存和临时表空间。

原因分析:

  • ROW_NUMBER() 的排序操作会导致全表排序
  • PARTITION BY 会将数据拆分成多个分区,每个分区都需要排序。

解决方案:

  1. 减少分区的数量:尽量减少 PARTITION BY 中的分区数量。
  2. 索引优化:为 ORDER BY 字段(如 CZSJ)创建索引,避免全表排序
  3. 分批查询:如果只关心 rn = 1,可以将查询重写为嵌套子查询

 

5:NULL 处理问题

PARTITION BYORDER BY 中的NULL 值处理不当,导致无法按照预期的逻辑进行排序。

常见的症状:

  • 使用 ORDER BY 时,NULL 排在最前面或最后面
  • 使用 PARTITION BY 生成的分区数量过多,NULL 被视为一个单独的分区

解决方案:

  1. 使用 NVL、COALESCE:将 NULL 替换为一个合理的默认值。
  2. ORDER BY 中控制 NULLS:指定 NULLS FIRSTNULLS LAST

示例代码:

ROW_NUMBER() OVER (PARTITION BY NVL(BGQYSJZBH, A.BH) ORDER BY CZSJ DESC NULLS LAST) AS rn

总结

问题原因解决方案
分区过多PARTITION BY 不合理使用 NVL 替换 CASE
排序不稳定ORDER BY 字段不唯一加入唯一的 ID 排序
WHERE 不生效WHERE 在窗口函数之后用 CTE 处理窗口函数
性能低下数据量大,排序缓慢加索引,减少分区
NULL 处理不当NULL 被独立为分区使用 NVL 替换 NULL
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大大怪~将军

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值