在代码提交前,怎么把高风险 SQL 拦下来?
SlowQL SQL审核工具: 在代码提交前,就把高风险 SQL 拦下来
最近发现一个有趣的开源项目, 分享给大家, 如果你还在为 SQL 安全审计的事情而烦恼, 务必仔细看完.
https://github.com/makroumi/slowql
数据库事故,80%根本不该在线上发现:把 SQL 风险扼杀在提交前,才是 DBA 和开发者真正的分工重构
你以为数据库问题,应该靠监控、慢日志、AWR、审计平台去兜底?
错。 等问题进入数据库,成本就已经高了一个量级。
真正成熟的团队,不是“线上发现 SQL 问题后快速救火”,而是在代码提交前,就把高风险 SQL 拦下来。
一、“上线后再看 SQL”,是落后的治理方式
先讲结论:
SQL 不是运行时对象,它首先是源代码资产。
只要它是源代码资产,就应该接受和 Java、Go、Python 一样的静态检查、规则治理、CI 门禁和基线管理。SlowQL 这类工具的价值,不在于“帮你扫几条 SQL”,而在于把数据库治理从“人肉经验”升级为“工程系统”。
为什么这个判断成立?因为从第一性原理看,数据库问题主要分成三类:
语义层风险:比如空值判断错误、危险动态拼接、权限或对象引用不当。 结构层风险:比如表、列、索引、迁移顺序、跨文件依赖变更造成的破坏。 工程层风险:比如 SQL 藏在应用代码、模板、迁移脚本、dbt 模型里,没人能一次看全。
如果问题属于这三类之一,那么它就不必等到执行期才发现。只要能在源码层构建规则、解析关系、建立上下文,就能在提交前发现相当一部分问题。SlowQL的定位正是如此:它是一个离线 SQL 静态分析器,不需要连接数据库,针对 SQL 源文件、迁移脚本、dbt/Jinja 模板以及应用代码里的 SQL 字符串做分析,并内置 279 条规则,覆盖 14 种 SQL 方言。
这件事为什么值得认真做?因为代价是真金白银。IBM《2024 Data Breach Report》显示,全球数据泄露平均成本已经达到 488 万美元,而且 70% 的受访组织表示业务运营受到中度或重度影响。另一边,CISQ 2022 报告估算,美国“低质量软件”的成本至少达到 2.41 万亿美元,其中技术债约 1.52 万亿美元。数据库层面的 SQL 失误,恰恰属于最典型、最隐蔽、又最容易滚成技术债的部分。
所以真正的问题不是“要不要扫描 SQL”,而是“你准备把数据库风险拦在哪一层”。
二、DBA、架构师、开发者,为什么都该关心这件事
1)对 DBA 和架构师:这是“治理左移”,不是“权限下放”
很多 DBA 天然反感“开发自己管 SQL 质量”,担心结果是标准变松、事故变多。
但如果你仔细看,这类工具的核心不是放权,而是把 DBA 的经验沉淀成规则。
SlowQL 支持组织自定义规则,既可以用 YAML,也可以用 Python 插件;而且规则与内置规则一起参与报告、抑制和输出。这意味着 DBA 可以把“禁止 SELECT * 扫超大表”“禁止某类 DDL 在业务时段出现”“禁止使用某类高危函数”写成制度化规则,而不是靠 code review 里一句“下次注意”。
这不是削弱 DBA,恰恰是在放大 DBA。
因为最昂贵的 DBA,不是会救火的人,而是能把组织经验变成可复制约束的人。
2)对应用开发者:这不是多一个工具,而是少背很多锅
开发最怕什么?
不是报错,而是SQL 没报错,但上线后拖垮系统、打爆成本、埋下合规雷。
SlowQL 的规则覆盖六大维度:安全、性能、可靠性、质量、成本、合规。其中安全 61 条、性能 56 条、可靠性 35 条、质量 40 条、成本 33 条、合规 18 条。它不是只盯“跑得慢”,而是把“能不能进生产”作为一个整体判断。
这点很关键。因为开发者写 SQL 时,最常掉进三个认知陷阱:
以为能跑就是对 以为 explain 正常就安全 以为代码 review 看过就够了
实际上,很多问题不是“当前环境能不能跑”,而是“规模放大后会不会炸”“换方言后会不会变味”“迁移后会不会把别的 SQL 打断”。SlowQL 的跨文件分析、迁移理解和方言感知,正是补这部分短板。它能识别 DDL、视图、过程之间的关系,也能理解 Alembic、Django migrations、Flyway、Liquibase、Prisma Migrate、Knex 等迁移框架的顺序和依赖。
三、这套思路为什么成立:前提条件是什么
这里不能盲吹。
“静态分析能显著降低数据库风险”成立,有前提。
前提一:你的 SQL 必须是“可被治理的资产”
也就是 SQL 至少存在于这些位置之一:
.sql文件迁移脚本 dbt/Jinja 模板 应用代码中的 SQL 字符串
SlowQL 可以从 Python、TypeScript/JavaScript、Java、Go、Ruby 中提取嵌入的 SQL,甚至能处理 Python f-string、模板字面量这类动态构造场景,并标记潜在注入风险。
前提二:你的主要问题属于“源码层可判定问题”
例如:
危险模式 明显反模式 结构引用错误 迁移破坏 方言不当使用 合规或成本禁忌项
这类问题非常适合静态分析。
但如果你的问题主要来自数据分布、运行时参数、统计信息失真、锁竞争、资源争用,那就不是它单独能解决的。此时仍然需要执行计划分析、监控、压测和数据库观测平台。
前提三:组织愿意把规则接入流程,而不是停留在“偶尔手工跑一下”
工具只有接入以下链路,价值才会释放:
本地 pre-commit CI 门禁 PR 注释 / GitHub code scanning 基线机制 团队级规则配置
SlowQL 支持 GitHub Actions、pre-commit、SARIF、JSON/HTML/CSV 导出、失败阈值,以及 LSP/VS Code 集成。SARIF 结果还能被 GitHub 代码扫描读取并显示为告警。
四、如果这些前提崩塌,观点就必须调整
这才是严谨。
情况 1:你的 SQL 大量动态拼接,且运行时形态依赖业务参数
那就别幻想“静态分析包治百病”。
此时更合理的做法是:
先用静态分析抓注入风险、拼接坏味道、显式反模式 再用真实流量回放、慢 SQL 采样、执行计划回归做二次校验
情况 2:你的数据库问题主要来自负载和数据规模变化
比如在测试环境毫无问题,线上 10TB 数据一跑就死。
那重点应该转向:
统计信息管理 索引策略 分区设计 SQL Plan Baseline / Hint 治理 压测与容量规划
静态分析只能做“前置筛查”,不能替代生产级性能工程。
情况 3:你的组织没有统一规范
那直接上全量强门禁,大概率翻车。
正确姿势不是“一刀切”,而是先基线、再增量。
SlowQL 提供 Baseline 模式,把现有存量问题记录到 .slowql-baseline,后续只盯新增问题;同时支持基于 Git 只分析变更文件,比如 --git-diff 或 --since main。这非常适合老系统渐进治理。
五、这类工具最值得关注的,不是“扫描”,而是三种治理能力
能力一:跨文件理解数据库变更
多数 SQL 检查工具只能“看单条语句”。
但线上事故经常不是单条 SQL 的问题,而是:
某个迁移删了列 某个视图改了定义 某段查询还在引用旧对象
SlowQL 的跨文件 SQL 分析和迁移上下文理解,能识别这种“你改 A,炸的是 B”的风险。这个能力,比单纯 lint 重要得多。
能力二:把数据库规范产品化
它支持按严重级别、维度、方言、规则做配置,也支持禁用、提级、降级某些规则。配置可以放在 slowql.toml、slowql.yaml、pyproject.toml 等文件里。
这意味着你可以把规范变成真正可执行的政策。例如:
PostgreSQL 团队把 SECURITY DEFINER风险拉高MySQL 团队把 utf8与utf8mb4问题列为高优先级BigQuery 团队重点盯 SELECT *带来的成本风险合规项目打开 GDPR 框架规则
能力三:能修的就安全修,不能修的别乱修
自动修复最怕“帮倒忙”。
SlowQL 在 README 里明确强调:只做精确文本替换,不做基于猜测的启发式改写;所有自动修复都标记为 FixConfidence.SAFE,并且支持先 --diff 预览,再 --fix 应用,还会生成 .bak 备份。
这是对的。
数据库领域最危险的自动化,不是不会修,而是自以为会修。
六、实操:一个团队该怎么把它落地,而不是“装完就吃灰”
下面给你一套可直接落地的路径。
第 1 步:本地先跑起来,别一上来就 CI 卡死
安装:
pipx install slowql
# 或
pip install slowql
最小运行:
slowql queries.sql
如果你的 SQL 不在独立文件里,而是在应用代码中:
slowql src/app.py src/services/
如果你有 DDL,可以直接加 schema 做结构校验:
slowql queries.sql --schema schema.sql
这些能力都来自官方 README:支持离线分析、应用代码 SQL 提取,以及基于 DDL 的表/列/索引校验。
第 2 步:先做“增量治理”,别碰存量烂账
对老项目,上来全扫,团队只会有两个反应:
第一反应:这工具太吵 第二反应:先关掉再说
更聪明的方式是先建立基线:
slowql queries/ --update-baseline
之后只关注新增问题。
如果在 Git 仓库里运行,只分析变更文件:
slowql . --git-diff
# 或
slowql . --since main
这套组合拳的本质是: 不跟历史债务正面硬刚,只阻止新债继续长出来。
第 3 步:把门禁规则分层,不要一个阈值管天下
README 里支持 --fail-on critical|high|medium|low|info|never。
建议别拍脑袋,按角色分层:
对核心交易库 / 核心链路
slowql --non-interactive --input-file sql/ --schema db/schema.sql --fail-on high --format github-actions
对普通业务库
先从 medium 告警但不阻塞开始,跑一段时间再提级。
对数据分析 / 数仓场景
把“成本”维度规则重点打开,尤其是 BigQuery、Snowflake、Redshift 相关规则。SlowQL 本身就区分了成本维度,并带有云数仓优化类规则。
一句话:门禁不该一刀切,而该按业务价值和风险分层。
第 4 步:把 DBA 规范写进配置,而不是写进 wiki
例如可以在 slowql.yaml 或 pyproject.toml 中做类似配置:
severity:
fail_on:high
warn_on:mediumanalysis:
dialect:postgresql
enabled_dimensions:
-security
-performance
-reliability
disabled_rules:
-PERF-SCAN-001
severity_overrides:
QUAL-NULL-001:critical
schema:
path:db/schema.sql
output:
format:console
show_fixes:true
compliance:
frameworks:
-gdpr
这不是照着抄配置,而是在表达一个治理原则:
规范只有进入机器执行层,才不再依赖“谁今天 review 得认真”。
第 5 步:允许例外,但例外必须被显式记录
任何治理系统都不能假设“规则永远比业务更懂现场”。
所以要允许抑制,但必须留下证据。
SlowQL 支持行级、下一行、代码块、整文件的内联抑制,例如:
SELECT * FROMarchive; -- slowql-disable-line PERF-SCAN-001
或者:
-- slowql-disable-next-line SEC-INJ-001
SELECTid, token FROM sessions WHEREid = $1;
这件事很重要。
因为成熟治理不是“零例外”,而是例外显式化、可审计、可回溯。
第 6 步:接 GitHub,不要让报告只躺在终端里
如果你的研发流程在 GitHub,最实用的接法有两种。
方式 A:GitHub Action
-uses:makroumi/slowql-action@v1
with:
path:"./sql/**/*.sql"
schema:"db/schema.sql"
fail-on:high
format:github-actions
方式 B:导出 SARIF,让 GitHub code scanning 接收
SlowQL 支持 sarif 输出;GitHub 官方文档也说明,第三方分析工具可以通过 SARIF 2.1.0 把结果显示为代码扫描告警。
这一步的价值不是“更炫”,而是让 SQL 风险进入你现有的工程闭环:
PR 能看到 安全团队能看到 平台团队能统计 历史趋势能追踪
治理,最怕的是“跑过一次,但谁也没看见”。
七、给两类读者的直接建议
给 DBA / 架构师
别再把自己定位成“最终审批人”。
你真正该做的是三件事:
把事故经验沉淀为规则 把规则挂进 CI 把例外机制设计清楚
你的价值,不在最后挡一次风险,而在于让团队系统性少犯同类错误。
给开发者 / 数据库用户
别把 SQL 当字符串。
只要 SQL 进入仓库,它就应该像代码一样被扫描、解释、门禁、追踪复杂度和风险。README 里甚至已经支持复杂度评分、趋势跟踪、终端可视化谱系,这说明趋势非常明确: SQL 正在从“附属物”变成“一等工程资产”。
八、最后一句狠话
很多团队口口声声说“数据库最重要”,
但真正涉及数据库变更时,流程却还停留在:
人工 review 经验口传 上线后观察 出事后复盘
这不是重视数据库。
这叫把数据库当运维兜底对象,而不是工程治理对象。
真正先进的做法,是把 SQL 风险管理前移到开发期、提交期、合并期。
不是因为这样“看起来更 DevOps”,
而是因为数据库问题一旦进入生产,代价通常已经不是技术问题,而是业务问题、成本问题、甚至合规问题。
你怎么看?
你所在的团队,SQL 质量现在主要靠 DBA 经验、代码评审,还是已经进入 CI 门禁了?
欢迎在评论区说说:你最想先拦住的那一类 SQL 问题,究竟是什么。