窗口函数无结果需先检查partition by与order by组合逻辑:partition by决定分组,缺失则全表为一组;order by决定窗口内顺序,缺失时postgresql允许但结果不可靠、mysql 8.0+直接报错;稳定排名应加二级排序如order by created_at, id。

窗口函数写完没结果?先检查 PARTITION BY 和 ORDER BY 的组合逻辑
窗口函数不是“加个 OVER() 就能跑”,最常见的情况是返回全 NULL 或结果和预期严重不符。根本原因往往出在分区与排序的配合上:比如用 ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at) 统计用户行为序号,但 created_at 有大量重复值且未加二级排序,会导致序号分配不稳定甚至跳变。
-
PARTITION BY决定“分几组”,不写就相当于全表一个窗口,容易误算累计值 -
ORDER BY在窗口内决定计算顺序,缺失时多数数据库(如 PostgreSQL)允许但结果不可靠;MySQL 8.0+ 则直接报错Window 'w' lacks an ORDER BY clause - 需要稳定排名时,建议补全二级排序,例如
ORDER BY created_at, id,避免因主键缺失导致相同时间戳下行为不可预测
CTE 递归查树形结构卡死?注意循环引用和层级限制
用 WITH RECURSIVE 查组织架构或评论回复链时,看似语法对了,一执行就超时或返回极少量数据,大概率是递归没终止。SQL 标准不自动检测环路,PostgreSQL 和 SQL Server 需手动设 MAXRECURSION(后者用 OPTION (MAXRECURSION n)),而 MySQL 8.0 默认只跑 1000 层,超出就中断并报错 Recursive query aborted after 1000 iterations。
- 必须在递归 CTE 的
WHERE条件中显式排除自引用,比如parent_id != id,否则一条坏数据就能拖垮整个查询 - 加
depth计数列,并在递归分支里限制depth ,比依赖全局配置更可控 - 如果表里存在双向父子关系(A 是 B 父节点,B 又是 A 父节点),索引也救不了——得先清洗数据,再查
JSON_EXTRACT 返回 NULL?别急着改数据,先看路径语法和字符集
MySQL 的 JSON_EXTRACT 或 PostgreSQL 的 ->> 拿不到值,90% 不是 JSON 本身有问题,而是路径写法或字段类型踩了坑。比如字段存的是 '{"name": "张三"}'(带单引号字符串),但类型是 VARCHAR 而非 JSON,MySQL 就会静默失败,返回 NULL 而不报错。
- MySQL 中用
JSON_VALID(col)先确认字段内容是否真为合法 JSON,别信业务代码写的“已转 JSON” - 路径里含中文或特殊字符时,MySQL 要求用双美元符写法:
JSON_EXTRACT(data, '$."用户信息".姓名'),单引号或漏掉点号都会失效 - PostgreSQL 对大小写敏感,
data->>'Name'和data->>'name'是两个世界,别靠猜
UPDATE 关联子查询慢到无法接受?优先考虑 JOIN 写法而非嵌套 (SELECT ...)
写 UPDATE t1 SET x = (SELECT y FROM t2 WHERE t2.id = t1.ref_id) 在数据量过万后明显变慢,不是因为子查询逻辑错,而是多数数据库(尤其 MySQL 5.7 及以前)会对 t1 每行都执行一次子查询,O(n²) 复杂度直接拉垮。
- MySQL 改成
UPDATE t1 JOIN t2 ON t1.ref_id = t2.id SET t1.x = t2.y,执行计划立刻从 “dependent subquery” 变成 “ref” - PostgreSQL 不支持 UPDATE + JOIN 语法,得用
UPDATE t1 SET x = t2.y FROM t2 WHERE t1.ref_id = t2.id,FROM 子句位置不能错 - 无论哪种写法,确保
t2.id和t1.ref_id都有索引,否则 JOIN 也白搭
复杂点在于:窗口函数的排序稳定性、递归 CTE 的环路防御、JSON 路径的引号嵌套规则、UPDATE 关联的引擎差异——这些地方不写错,功能才真正可用。









