PostgreSQL码农集散地

在代码提交前,怎么把高风险 SQL 拦下来?

SlowQL SQL审核工具: 在代码提交前,就把高风险 SQL 拦下来

最近发现一个有趣的开源项目, 分享给大家, 如果你还在为 SQL 安全审计的事情而烦恼, 务必仔细看完.

https://github.com/makroumi/slowql

数据库事故,80%根本不该在线上发现:把 SQL 风险扼杀在提交前,才是 DBA 和开发者真正的分工重构

你以为数据库问题,应该靠监控、慢日志、AWR、审计平台去兜底?
错。 等问题进入数据库,成本就已经高了一个量级。
真正成熟的团队,不是“线上发现 SQL 问题后快速救火”,而是在代码提交前,就把高风险 SQL 拦下来。


一、“上线后再看 SQL”,是落后的治理方式

先讲结论:

SQL 不是运行时对象,它首先是源代码资产。
只要它是源代码资产,就应该接受和 Java、Go、Python 一样的静态检查、规则治理、CI 门禁和基线管理。SlowQL 这类工具的价值,不在于“帮你扫几条 SQL”,而在于把数据库治理从“人肉经验”升级为“工程系统”。

为什么这个判断成立?因为从第一性原理看,数据库问题主要分成三类:

  1. 语义层风险:比如空值判断错误、危险动态拼接、权限或对象引用不当。
  2. 结构层风险:比如表、列、索引、迁移顺序、跨文件依赖变更造成的破坏。
  3. 工程层风险:比如 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:medium

analysis:
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 / 架构师

别再把自己定位成“最终审批人”。
你真正该做的是三件事:

  1. 把事故经验沉淀为规则
  2. 把规则挂进 CI
  3. 把例外机制设计清楚

你的价值,不在最后挡一次风险,而在于让团队系统性少犯同类错误。

给开发者 / 数据库用户

别把 SQL 当字符串。
只要 SQL 进入仓库,它就应该像代码一样被扫描、解释、门禁、追踪复杂度和风险。README 里甚至已经支持复杂度评分、趋势跟踪、终端可视化谱系,这说明趋势非常明确: SQL 正在从“附属物”变成“一等工程资产”。


八、最后一句狠话

很多团队口口声声说“数据库最重要”,
但真正涉及数据库变更时,流程却还停留在:

  • 人工 review
  • 经验口传
  • 上线后观察
  • 出事后复盘

这不是重视数据库。
这叫把数据库当运维兜底对象,而不是工程治理对象。

真正先进的做法,是把 SQL 风险管理前移到开发期、提交期、合并期。
不是因为这样“看起来更 DevOps”,
而是因为数据库问题一旦进入生产,代价通常已经不是技术问题,而是业务问题、成本问题、甚至合规问题。


你怎么看?
你所在的团队,SQL 质量现在主要靠 DBA 经验、代码评审,还是已经进入 CI 门禁了?
欢迎在评论区说说:你最想先拦住的那一类 SQL 问题,究竟是什么。