用 AI 做 SQL 性能优化建议,怎么避免它给出错误的改写?
面试怎么回答
AI 优化 SQL 常见的问题是改变语义,比如 NOT IN 改 LEFT JOIN 在有 NULL 时不等价、外连接被改成内连接;不了解数据分布和引擎版本,给出泛泛的建议。我的做法是输入给足证据:SQL、执行计划、各阶段耗时、Shuffle 量、Task 耗时分布、表的统计信息和引擎版本,让它定位真正的瓶颈。输出分成不改语义的参数和配置调整,以及 SQL 改写,改写必须说明为什么等价、前提是什么。上线前一定验证:在采样数据或单分区上对比行数、汇总值和按主键的差异,构造 NULL、重复值、空分区等边界数据,用相同资源对比性能,再走代码评审。可以把采集指标和结果对比做成工具,并跟踪建议的采纳率和效果。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
把一条跑了 2 小时的 SQL 丢给大模型,它很快给出了优化建议:改写子查询、调整 Join 顺序、加 Hint。但改写后的 SQL 跑得快了,结果却和原来不一样。面试官问这题,想看你怎么用 AI 提效,同时守住「结果正确」这条底线。
AI 优化 SQL 常见的问题
- 语义改变:
NOT IN改成LEFT JOIN ... IS NULL,在有 NULL 值时结果不同;LEFT JOIN改成INNER JOIN丢了数据;去重逻辑被「优化」掉; - 不了解数据分布:建议用广播 Join,但小表其实有几个 GB;
- 不了解引擎和版本:给出的参数或 Hint 在你的引擎版本里不存在或者已经默认开启;
- 只看 SQL 文本:没有看执行计划和运行指标,建议是泛泛的「最佳实践」。
正确的做法:给证据,做验证
输入要充分
- SQL 本身 + 执行计划(EXPLAIN);
- 运行指标:各阶段耗时、Shuffle 数据量、数据倾斜情况(Task 耗时分布)、溢写;
- 表的统计信息:行数、分区数、关键字段的基数;
- 引擎类型和版本、集群资源配置。
这样 AI 能定位真正的瓶颈,比如「第 3 个 Stage 有一个 Task 处理了 80% 的数据,是 Join key 倾斜」。
输出要分类
- 不改语义的优化:参数调整、加分区过滤(如果原本就该有)、开启 AQE、调整并行度;
- 改写 SQL:必须说明改写前后为什么等价,以及在什么前提下等价(比如「假设 user_id 不为 NULL」)。
验证必须做
- 在采样数据或者一个分区上,对比原 SQL 和新 SQL 的结果:行数、关键字段的汇总值、按主键的逐行差异;
- 准备边界数据:NULL、重复值、空分区;
- 对比性能时用相同的资源和数据量;
- 通过代码评审再上线。
把它做成工具
- 自动采集执行计划和运行指标,减少人工整理;
- 内置结果一致性对比脚本;
- 记录每条建议是否被采纳、优化效果如何,用来评估和改进。