当前位置:首页 > 娱乐

SQL扫描工具

上周排查一个线上慢查询,描工DBA甩过来一句:“你们代码里那个 SELECT * FROM orders WHERE user_id = ?描工 扫了 200 万行。”我盯着屏幕愣了两秒,描工不是描工 SQL 写错了,是描工索引没建对。但问题是描工——这种事儿,靠人眼 review 根本防不住。描工于是描工我又把 SQL 扫描工具翻出来折腾了一遍。

这类工具的描工核心逻辑其实不复杂:解析 SQL 语句,提取表名、描工字段、描工条件、描工函数调用,描工再跟数据库元数据(索引、描工行数、描工字段类型)做比对,最后按规则打分。听起来像静态分析,但真正落地时,麻烦全在细节里。

它到底在扫什么?

我拿 sqlmap 的 --parse-errors 做过实验,那玩意儿主要盯注入,跟性能扫描是两码事。真正干性能扫描的,比如 pt-query-digest、soar、SQLAdvisor,关注点集中在几类问题上:

  • 全表扫描:WHERE 条件字段没索引,或者索引失效(比如对字段用了函数 DATE(create_time) = '2024-01-01')。
  • 隐式类型转换:user_id 是 varchar,你传个数字 123,MySQL 会把字段转成数字再比,索引直接废掉。
  • 排序和分组:ORDER BY 的字段不在索引里,或者 GROUP BY 跟索引顺序不一致,触发 filesort。
  • 子查询和 JOIN:IN (SELECT ...) 这种写法在旧版 MySQL 里可能被改写成半连接,但工具会标红提醒。

我见过最离谱的一个案例:某业务 SQL 里写了 WHERE status != 0,而 status 字段只有 0 和 1 两个值。工具直接判定“索引选择性极低”,建议改写成 status = 1。改完查询时间从 1.2 秒降到 80 毫秒。这种规则,人写 review 清单也能列,但架不住天天有人忘。

工具怎么用才不添乱

我试过把 soar 挂到 CI 里,每次提交 SQL 文件就自动跑一遍。结果第一天就炸了——历史遗留的 300 多条 SQL 里,有 40 多条被标成“高危”。团队里有人直接开喷:“这工具是不是有病?我这条 SQL 跑了三年都没事。”

后来我调了规则阈值。比如把“全表扫描”的告警条件从“扫描行数 > 1000”改成“扫描行数 > 表总行数的 30%”,并且只对新增 SQL 做强制拦截,存量 SQL 只记录不报错。工具是死的,人是活的。你得让它先跑一段时间,收集真实反馈,再决定哪些规则该严、哪些该松。

另一个坑是解析兼容性。SQLAdvisor 对 MySQL 8.0 的 CTE(WITH 子句)支持很差,遇到 WITH tmp AS (...) SELECT ... 直接解析失败,然后给你吐一堆乱码。我现在的做法是:工具只做第一层过滤,把明显有问题的 SQL 挑出来,剩下的交给 EXPLAIN 人工确认。别指望一个工具能覆盖所有场景。

一个具体的扫描输出

拿 soar 举例,输入一条 SQL,它返回的 JSON 里会有 heuristicSuggest 字段。比如这条:

SELECT id, name FROM users WHERE age + 1 > 18; 

工具会提示:“条件字段 age 参与了运算,索引失效。建议改为 age > 17。” 这种改写建议,比单纯说“索引失效”有用得多。但注意,age > 17 和 age + 1 > 18 在边界值上可能不等价(比如 age 是浮点数时),工具不会告诉你这个。所以最终还得靠人判断。

我现在习惯把扫描工具当成“SQL 语法警察”,而不是“性能优化大师”。它能帮你抓住 80% 的低级错误,剩下 20% 得靠 EXPLAIN、慢日志和业务理解。上周那个 200 万行的慢查询,工具其实早就报过警——只是当时没人看报告。工具没毛病,用工具的人有毛病。

分享到: