资讯详情

资讯详情

从 0 到 1 搭好 sqlc 质量门禁:用 vet 规则拦住坏 SQL

从 0 到 1 搭好 sqlc 质量门禁用 vet 规则拦住坏 SQL【免费下载链接】sqlcGenerate type-safe code from SQL项目地址: https://gitcode.com/gh_mirrors/sq/sqlc上周一个查最近 7 天订单的接口上线后开始变慢定位半天才发现新加的查询没走索引全表扫了 2000 万行。问题不在代码而在 SQL——而你的代码评审流程恰好没有人专门看 SQL。sqlc 的vet子命令就是为解决这件事设计的它把质量规则写进sqlc.yaml每次跑sqlc vet时逐条校验你的查询不合格的查询直接报错、退出码非 0。这篇文章带你配好一套 sqlc 质量门禁让这类问题在进主干之前就被拦住。30 秒看懂 sqlc vetsqlc vet会读取 sqlc 配置中定义的规则把每条规则当成一个判断表达式逐条套在包的每条查询上表达式结果为true就报一条错误。规则用 CEL 表达式书写所以既能查文本模式也能查执行计划。它能检查什么先看这张表检查项作用是否需要连数据库查询文本匹配拦截DELETE、裸SELECT *这类反模式否查询元信息限制参数个数、禁用某类cmd如:exec否sqlc/db-prepare内置规则让数据库真正PREPARE每条查询列不存在、类型不匹配当场暴露是postgresql.explain/mysql.explain拿真实EXPLAIN执行计划判断成本、顺序扫描、是否走主键是PostgreSQL / MySQL不连库就能跑的规则适合所有项目连库后的检查才谈得上质量门禁的完整形态。从零搭一套质量检查整套配置就放在sqlc.yaml里参考 vet 文档。下面按动作展开。连上数据库。在sql包下加database.uri并启用内置规则version: 2 sql: - schema: schema.sql queries: query.sql engine: postgresql database: uri: postgresql://postgres:postgreslocalhost:5432/postgres rules: - sqlc/db-prepare跑sqlc vet时sqlc 会连接这个库并对每条查询执行PREPARE。注意sqlc 不会自动建表库里的 schema 必须和schema.sql一致先用你现有的迁移工具把表建好或者配置 managed databases 让 sqlc 自动创建带正确 schema 的临时库。写规则。规则定义在全局的rules:列表每个规则三个字段name唯一标识、message命中时报给开发者的话、ruleCEL 表达式。然后在你希望生效的包下用rules:按名字启用——定义了但没启用的规则不会跑rules: - name: no-full-scan message: 列表查询请限制返回行数 rule: query.cmd many !query.sql.contains(LIMIT) - name: cost-guard message: 查询成本超阈值请检查执行计划 rule: postgresql.explain.plan.total_cost 300.0校验。在本地跑sqlc vet每条命中的查询会打印成文件名: 查询名: 规则名: message的形式只要有命中退出码就是 1。想给个别查询豁免在 SQL 注释里加一行即可/* name: BackfillFix :exec */ /* sqlc-vet-disable cost-guard */ UPDATE orders SET status paid WHERE id ?;sqlc-vet-disable不带参数则跳过该查询的所有规则。规则表达式怎么写规则表达式能拿到三类变量config引擎、schema 路径等、querySQL 文本、名字、cmd、参数列表、postgresql.explain/mysql.explain执行计划仅连库且引擎匹配时可用。拆三个高频写法查文本与元信息不连库。query变量对应结构很简单字段含义query.sql查询 SQL 全文支持.contains()等字符串操作query.name/* name: ... */注解里的名字query.cmdmany/one/exec等query.params.size()参数个数组合起来就能表达多行查询必须带 LIMITrule: query.cmd many !query.sql.contains(LIMIT)查执行计划成本连 PostgreSQL。sqlc 会对查询跑EXPLAIN (VERBOSE, COSTS, BUFFERS, FORMAT JSON)并解析成结构体plan.total_cost是最常用的成本估计值rule: postgresql.explain.plan.total_cost 300.0查顺序扫描连 PostgreSQL。plan.node_type是执行计划的节点类型判断顶层是否为全表扫描rule: postgresql.explain.plan.node_type Seq ScanMySQL 侧结构不同成本在query_block.cost_info里注意先判存在再取值rule: has(mysql.explain.query_block.cost_info) double(mysql.explain.query_block.cost_info.query_cost) 2.0字段拿不准时别猜设SQLCDEBUGdumpexplain1再跑sqlc vetsqlc 会把每条查询的原始EXPLAINJSON 打印出来照着 JSON 写表达式就行。完整字段定义见 vet 参考 和仓库protos/vet/vet.proto。接入 CI/CD 让检查自动跑本地跑得通还不够门禁必须挂到流水线上。最小命令序列是sqlc vet规则校验加sqlc diff确认生成代码没被手改、没漏跑generate两个都失败即退出码 1天然适合当 CI 卡点name: sqlc on: [push] jobs: vet: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 - run: go install github.com/sqlc-dev/sqlc/cmd/sqlclatest - run: sqlc vet env: # 规则里用 ${VET_TEST_DB_URI} 这类占位符这里注入 CI 的库地址 VET_TEST_DB_URI: postgresql://postgres:postgreslocalhost:5432/postgres - run: sqlc diff用uri: ${ENV_VAR}把数据库地址交给环境变量本地和 CI 共用一份配置。vet的退出码直接决定这一步红不绿不需要额外脚本。这些坑我替你踩过了现象原因对策sqlc/db-prepare报错但本地查询明明能跑sqlc 不执行迁移库里的 schema 落后于schema.sql跑 vet 前先执行迁移或改用 managed databases 自动建临时库explain 类规则报database connection required用了postgresql.explain但包里没配database该包补database.uri只想查文本的话删掉 explain 规则某条规则误伤历史查询团队要求豁免规则一刀切老代码一时改不完查询上加sqlc-vet-disable 规则名精确豁免别用无参版跳掉全部检查阈值调多少没底拍脑袋设阈值要么全红要么全绿先SQLCDEBUGdumpexplain1看现有查询的真实成本分布取一个明显高于现状的起点再逐步收紧规则里直接引用 explain 字段部分查询报错不同查询的EXPLAINJSON 结构不同字段可能不存在引用前加has(...)判空参考 MySQL 那条写法的has() 组合团队规则越加越乱没人敢删规则没有 owner 和文档每条规则的message写清为什么禁 怎么改每季度按误报率清一次规则宁少勿滥一条总是红的规则会让开发者绕开vet整个门禁形同虚设。写在最后先不连库把文本类规则跑红、跑绿、跑进 CI确认稳定后再连库加sqlc/db-prepare和 explain 规则阈值从宽松起步逐步收紧。质量门禁不是一次会议搭出来的而是随查询一起长出来的。更多细节看 官方文档。【免费下载链接】sqlcGenerate type-safe code from SQL项目地址: https://gitcode.com/gh_mirrors/sq/sqlc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →