摘要:早上开例会,隔壁组亮出执行计划,全表扫描次数从九次掉到一次,CPU直降八成。
同事一条SQL把30秒干成0.5秒,我却还在加班调索引
早上开例会,隔壁组亮出执行计划,全表扫描次数从九次掉到一次,CPU直降八成。
老板当场问:为啥你俩写同一张宽表,差距能顶一辆特斯拉?
答案藏在一个很小的选择:子查询还是CTE。
先看清规则。
子查询像快递袋,一次用完就扔;CTE像可折叠收纳箱,能反复打开再合起。
简单过滤,用子查询最省事。
逻辑一旦超过三层,CTE立刻把代码切成一段段能看懂的小块,后续复用不用再拼积木。
很多人卡在性能。
子查询会被优化器改写成JOIN,运气好就飞快;运气不好,同一段子查询被执行器重复跑几遍,磁盘狂转。
CTE默认会把结果先存进内存或临时文件,省得重复算,却可能撑爆缓存。
PostgreSQL 12以后多了WITH … AS … NOT MATERIALIZED,告诉数据库别急着落盘,能省一大笔I/O。
SQL Server用户更喜欢临时表加索引,大数据量分阶段处理也稳。
容易踩的坑有三。
NOT IN 碰见空值就全军覆没,换成NOT EXISTS立刻复活。
多层嵌套子查询有时让优化器放弃索引,直接扫全表。
几百万行的CTE一次性落盘,内存报警比群里红包还快,分批或加过滤条件就能缓和。
把视角拉远。
窗口函数叠加CTE,能把复杂排名、环比、同比写成三小段,运行照样快。
数据仓库里,把子查询结果写成物化视图,每天跑一次,报表直接读视图,高峰不再堵塞。
分布式数据库时代,CTE还能被拆成子任务并行跑,再合并结果,单机时代的瓶颈被平行计算直接抹平。
一条SQL值不值钱,就看读的人能不能三分钟看懂、三小时不改。
写之前先问自己:这段逻辑只出现一次,还是以后天天被同事抄?
答案清晰,选子查询还是CTE就不再纠结。
来源:古镇木雕赏精巧艺