开启 3 天免费试用
注册即可免费体验全部高级功能。
*仅限新用户;每位用户只能获得一次试用。


要安全地用 AI 编写并检查 SQL,就给模型一份获批的 schema 和精确的业务问题,要求用参数而非字符串拼接传值,并把执行限制在最小权限的只读沙箱或一次性副本中。信任结果之前,先审查执行计划,再用独立设计的 fixture 核对行、join、空值、重复和聚合。
不要把 AI 工具直接连到生产数据库当作学习捷径。在受控边界内使用 AI的流程同样适用,但数据库访问需要更强的身份、数据和副作用控制。
关键要点
- 生成 SQL 前,先定义业务问题、行粒度、schema 和假设。
- 通过数据库驱动的参数接口把代码和值分开。
- 按读写行为和可能的副作用给每条语句分类。
- 使用一次性数据库或最小权限的只读身份,而不是生产凭证。
- 先审查执行计划,再用合成 fixture 和独立总计核对结果。
把起草和执行分开。模型可以根据 schema 上下文提出查询,但是否执行、在哪里执行,由经过审核的操作人员或受控应用决定。这样,一次解释上的错误就不会变成数据库操作。
OWASP 建议把使用参数化查询的预编译语句作为防御 SQL 注入的主要手段,因为它把 SQL 代码与传入的值分开定义。[1] 参数化不能证明查询回答了正确的问题,但能挡住一大类代码与数据混淆。
设置五道门禁:
| 门禁 | 必需证据 |
|---|---|
| 问题 | 已定义的指标、人群、时间窗口和行粒度 |
| 草稿 | 带 schema 限定的 SQL 及显式假设 |
| 安全 | 参数、读写分类、最小权限的执行身份 |
| 计划 | 已审查的算子、估算、过滤、join 和资源风险 |
| 结果 | 已核对的 fixture 行、总计、重复、空值和边界情况 |
每道门禁的输出都是下一道的输入。不要让聊天界面把它们藏进一个“运行此查询”按钮里。
分享 schema 之前,先用业务语言写下问题。“为每个活跃客户返回一行,包含上一个完整自然月的已付发票总额”比“显示月收入”清楚。
定义:
最昂贵的 SQL 错误大多始于含糊的粒度。把发票行 join 到多条状态事件上,即使每个子句都是合法 SQL,金额也可能成倍放大。把预期的唯一键写明。
在给出查询文本之前,先让模型陈述假设。例如:“invoices.id 唯一”“一个客户可能有多张发票”“时间戳以 UTC 存储”。对照 schema、约束、迁移和维护中的文档逐条核实。
如果不熟悉代码仓库,先用只读证据理清相关代码和数据路径。不要只凭应用里的变量名推断数据库契约。
提供表名、列名、类型、键、关系、相关约束和几行合成数据。写明数据库方言和你的环境支持的版本特性,但省略真实记录、凭证、主机名、连接字符串和敏感注释。
优先提供整理过的 schema 摘录,而不是完整的生产导出。删除个人数据和看起来像秘密的默认值。如果列名本身就透露敏感商业信息,就用关系等价、获批准的本地 fixture。
告诉模型不要编造缺失的列、索引、关系或枚举值。它的回答应分两部分:“查询草稿”和“未解决的 schema 问题”。依赖未解决关系的查询不能执行。
来自用户、请求、文件或上游系统的值,必须使用驱动的绑定参数接口。不要让模型手动转义字符串或把它们拼进 SQL。OWASP 的查询参数化指南展示了这一做法在常见语言和数据库接口中的写法。[2]
概念上,应优先采用:
SELECT customer_id, SUM(amount) AS paid_total
FROM invoices
WHERE status = :status
AND paid_at >= :period_start
AND paid_at < :period_end
GROUP BY customer_id;
占位符语法因驱动而异,请在你实际使用的库的官方文档中核实。
参数通常不能代替表名、列名、排序方向或 SQL 关键字。如果标识符必须可变,就在应用代码里把一小组获批输入映射到写死的标识符。不要把模型生成的任意标识符直接传给数据库。
参数化查询仍可能把每一行客户数据暴露给未获授权的调用方。租户范围、行级规则、数据库角色和应用授权要分别核实。AI 隐私风险指南可以帮你判断哪些数据根本不该进入提示词或 fixture。
不要只凭第一个可见的关键词分类。公用表表达式、函数、触发器、存储过程、扩展、临时对象、锁和 EXPLAIN ANALYZE 的行为都可能不同于普通读取。
使用三个实用类别:
| 类别 | 例子 | 默认处理 |
|---|---|---|
| 读候选 | 普通 SELECT、不执行的计划检查 | Review 后进入只读沙箱 |
| 状态或资源效果 | 加锁读取、临时对象、大范围扫描、会执行的计划分析 | 专用环境并设显式限制 |
| 写入或管理 | INSERT、UPDATE、DELETE、DDL、授权、有副作用的存储过程 | 独立变更流程和人工批准 |
PostgreSQL 事务把多个步骤组合成全有或全无的单元,并在完成前对其他事务隐藏中间变更。[3] 事务有助于管理原子性,但不会让错误的更新变得可以接受,也不保证外部副作用可以回滚。
绝不能把“之后回滚”当作未经审查写入的主要安全边界。错误的查询可能在你计划回滚之前就锁住资源、触发任务、调用易变函数或暴露数据。
最安全的学习环境是装有合成数据的本地或一次性数据库。预发环境副本可能仍含敏感记录,也可能触发集成,因此要核实它的数据和副作用边界。
必须查询真实数据库时,使用专用身份,只授予所需的 schema、表、列和操作。在模型控制范围之外设置语句超时、适当的行数上限、资源控制和日志。
PostgreSQL 支持只读事务模式,并在该模式下禁止许多数据变更命令,但其文档说明,这只是高层次的只读概念,并不能阻止所有磁盘写入。[4] 把它视为其中一层,而不是普遍保证。其他数据库的语义也各不相同。
此图描述的是操作流程,不能证明某个具体数据库、身份、函数或连接器是只读的。
审查所选列、join 键、过滤、空值行为、分组、排序、限制和子查询。留意意外的交叉 join、放在会放大行数的 join 之后的过滤条件、被 WHERE 谓词变成内连接的左连接,或使用了错误时区的日期边界。
如果数据库支持,先用不执行的计划命令。检查:
在 PostgreSQL 中,EXPLAIN ANALYZE 会真正执行查询,同时报告实际行数和耗时。[5] 不要把它当作无害的预览。只有在给底层语句和资源风险分类之后,才在获批环境中使用。
计划不是正确性的证明。快速的计划可能返回错误的行;正确的查询也可能对生产数据分布来说代价太高。
建一个能手工算出答案的小型合成数据集。每条重要规则至少对应一行:
运行生成的查询之前,先写下预期的行和总计。然后比较:
可以让 AI 帮你列出遗漏的情况,但不要让它在无人核对的情况下既算预期结果又写查询。使用 AI 测试设计流程构建回归 fixture,让判定依据独立于 SQL 实现。
一条安全的语句,也可能因应用代码拼接字符串、用错类型绑定值、使用高权限连接池、重试写入、在日志中记录敏感参数或返回无上限的结果而变得不安全。
检查最终的调用点:
对集成补丁应用 AI 生成代码执行前 Review清单。只审查裸 SQL,覆盖不到周边的权限和控制流。
如果任务需要更新数据,在执行之前就停止起草流程。要求有经过审查的迁移或运维手册、受影响行预览、备份或恢复计划、事务设计、并发分析、授权、监控和一位具名批准人。
使用不可变的输入,并把批准绑定到确切的查询、参数、目标身份、数据库和时间窗口。之后对查询的任何修改都会使批准失效。不要让模型在预览之后扩大影响范围。
查询产生意外的行或性能时,保留证据,并使用 AI 调试流程。没有稳定的判定依据,反复要求“更好的查询”,往往只是用一个隐藏假设换掉另一个。
只有在组织允许、并删除秘密和敏感商业细节之后才可以。优先提供最小的获批摘录,或等价的合成 schema。
不能。它有力地解决了值层面的代码与数据分离,但你仍需核实授权、数据暴露、标识符、查询逻辑、权限、资源使用和应用集成。
它是重要的一层,但不是完整的保证。要核实数据库特定的语义、函数行为、临时对象、资源影响、可访问的数据,以及连接实际使用的身份。
EXPLAIN 与 EXPLAIN ANALYZE 一样吗?不一样。在 PostgreSQL 中,普通 EXPLAIN 只显示计划、不运行查询,而 EXPLAIN ANALYZE 会执行查询并报告实际测量值。使用前请查阅你所用数据库的文档。
定义预期的行粒度和唯一键,比较每次 join 前后的行数,并用一对多的 fixture 测试。把分组小计与独立算出的总计核对。
学习或起草时不应默认这样做。使用一次性数据库或受控查询接口,并配合最小权限、明确批准、日志记录和独立的结果核对。
不能。事务语义因数据库而异,外部调用、序列、锁、通知或运维影响可能无法完全撤销。请审查具体系统的行为。
暂停执行,保留 fixture 和结果,先核实判定依据,再逐项检查粒度、join、过滤、空值、时间边界和重复。不要为了让查询通过而修改预期值。
延伸阅读:
免责声明:本文提供一般技术与安全信息,不构成数据库管理、法律、合规或财务建议。对有后果的数据系统,请使用合资格的复核人和组织的变更控制。
来源:
Sources checked 2026 年 8 月 24 日。
注册即可免费体验全部高级功能。
*仅限新用户;每位用户只能获得一次试用。