- 开发工具
- 数据库
【免费下载链接】soar
SQL Optimizer And Rewriter
soar(SQL Optimizer And Rewriter)是一个面向 MySQL 的 SQL 智能优化与改写工具,其能力覆盖语法检查、启发式规则评审、索引建议、Explain 解读、SQL 重写与多种报告输出。本文以仓库根目录的 CHANGES.md 变更日志为时间主线,逐项还原该工具从 2018 年 3 月架构设计到 2019 年 8 月的完整能力建设历程,并结合 advisor/、common/、ast/、database/ 等源码目录印证每一类能力的底层实现。读完本文,你将能够按功能域快速定位 soar 的规则体系、索引建议、测试环境与配置机制,并理解一个 SQL 优化工具在工程化与开源过程中需要解决的实际问题。
一、CHANGES.md 记录了什么:一份功能与修复双线并行的演进日志
CHANGES.md 覆盖 2018-03 至 2019-08 共 18 个月的开发记录,内容可归为四类:
- 能力新增:如语法检查、数据采样、Explain 解读、启发式规则、报告类型、SQL 重写、配置与日志模块;
- 规则修复:大量针对具体启发式规则(如 ARG.003、CLA.001、ARG.008)的边界场景修正;
- 底层基础设施替换:如 MySQL 驱动从 mymysql 迁移到 go-sql-driver、引入 go.mod、全量 vendor、CI 与测试框架建设;
- 开源与社区化:2018-09 首次技术分享、2018-10-20 在 OSCAR 对外正式开源发布。
从代码结构看,这些变更分别落在五个核心模块:advisor(评审与索引建议)、ast(基于 Vitess 与 TiDB Parser 的语法树处理)、common(配置、日志、工具函数)、database(Explain/采样/表结构信息获取)、cmd/soar(命令行入口)。下面按能力域逐层展开。
二、奠基期(2018-03 ~ 2018-05):从架构设计到四大基础能力
2.1 基本架构与 AST 底层函数
2018-03 完成了"基本架构设计",并"添加大量底层函数用于处理 AST",同时实现 "Insert、Delete、Update 转写成 Select 的基本函数" 与 "MySQL Explain 信息输出"。这三件事构成了 soar 后续全部能力的地基:
- 基于语法树的 SQL 分析(见 ast/ 目录下的 token.go、tidb.go、vitess.go);
- 将 DML 改写为 SELECT 以便在测试环境安全执行的机制(对应重写规则中的
dml2select); - 对执行计划的结构化解析(见 database/explain.go)。
2.2 语法检查、测试环境与元数据
2018-04 密集落地了"语法检查""测试环境""MySQL 元数据的获取""基于数据库环境信息给予索引优化建议""不依赖数据库元信息的简单索引优化建议""日志模块""配置文件"七项能力。
其中"测试环境"的设计一直沿用至今:配置项中同时存在online-dsn与test-dsn(见 common/config.go),allow-online-as-test允许在特殊情况下将线上环境直接当作测试环境,drop-test-temporary控制是否清理测试环境产生的临时库表。命令行入口 cmd/soar/soar.go 中env.BuildEnv()负责构建测试环境,并在程序退出时依据该开关清理临时对象。
2.3 数据采样与安全执行(2018-05)
2018-05 是能力爆发的一个月,新增了:
- 数据采样功能:通过
sampling、sampling-statistic-target(对应 PostgreSQL 的default_statistics_target)、sampling-condition三个配置项控制(common/config.go),实现在 database/sampling.go; - 语句执行安全检查:评审前判断 SQL 是否具备执行风险;
- DDL 语法检查与 DDL 测试环境执行:借助 TiDB Parser 对 DDL 类型语句进行解析与建议;
- 隐式数据类型转换检查:即后来反复修复的 ARG.003 规则的前身;
- 索引去重与前缀索引支持:前者演化为独立的
duplicate-key-checker报告类型,后者体现在索引建议对前缀长度的计算上; - SQL Pretty 输出:即
-report-type pretty与compress的底层逻辑。
同期还新增"SQL 执行超时限制"与"Explain 支持 last_query_cost",前者通过 DSN 的timeout/read-timeout/write-timeout(common/config.go)实现,后者对应show-last-query-cost配置与MaxQueryCost警告阈值。
三、启发式规则体系:数量扩张与边界修复并重
启发式规则是 soar 评审输出的核心。从 advisor/rules.go 可以看到规则按前缀分类:ALI(别名)、ARG(参数/谓词)、CLA(子句)、COL(列定义)、DIS(去重)、FUN(函数)、KEY(索引键)、KWR(关键字/命名)、LCK(锁)、LIT(字面量)、RES(结果集)、SEC(安全)、STA(标准)、TBL(表定义)。每条规则统一由Rule结构描述,包含编号、Severity 级别、摘要、说明文案、示例 SQL 与检测函数。
3.1 规则新增:CHANGES.md 中明示的五条规则
CHANGES.md 明确记录了以下新增规则:
| 规则编号 | 关注点 | 规则定义位置(advisor/rules.go) | 检测函数实现位置 |
|---|---|---|---|
| COL.018 | 建表语句中使用不推荐的字段类型(默认boolean,可用column-not-allow-type配置) | rules.go#L577-L584 | heuristic.go |
| RES.009 | 连续判断(如col = col = 'abc')疑似书写错误 | rules.go#L997-L1004 | RuleMultiCompare |
| SEC.004 | 发现常见 SQL 注入函数(SLEEP、BENCHMARK、GET_LOCK、RELEASE_LOCK) | rules.go#L1045-L1052 | RuleInjection |
| TBL.008 | 表定义相关问题 | rules.go#L1201 | — |
| KEY.010 | 全文索引不是银弹,需控制查询频率与并发度 | rules.go#L837-L844 | RuleFulltextIndex |
| ARG.012 | 一次性 INSERT/REPLACE 数据过多 | rules.go#L272-L279 | RuleInsertValues |
| KWR.004 | 不建议使用多字节编码字符(中文)命名 | rules.go#L869-L876 | RuleMultiBytesWord |
以 SEC.004 为例,其Content明确指出SLEEP(), BENCHMARK(), GET_LOCK(), RELEASE_LOCK()等函数常出现在 SQL 注入语句中、会严重影响数据库性能,这体现了 soar 的评审不仅是性能优化,还包含安全维度(同类的还有 SEC.001 TRUNCATE 谨慎使用、SEC.002 密码明文存储检查、SEC.003 高危操作备份提醒)。
3.2 规则修复:反复打磨的边界场景
CHANGES.md 中相当篇幅是规则修复记录,这些条目恰好勾勒出启发式检查从"能检"到"检得准"的过程:
- ARG.003(参数比较包含隐式转换,无法使用索引)是修复次数最多的规则。其规则定义在 rules.go#L200-L207,注释明确说明"该建议在 IndexAdvisor 中给",即真正检测逻辑位于 advisor/index.go 的
(*IndexAdvisor).RuleImplicitConversion。修复记录包括:INT 与 DECIMAL 类型比较(2019-08)、使用IN ()运算符时重复建议(2019-08)、bit 类型未按 int 配置导致误报 ARG.003(2018-12)、值类型不匹配检查 bug(2018-11)、字符集与 Collation 不一致时的隐式转换检查(2018-07); - CLA.001(最外层 SELECT 未指定 WHERE 条件):2019-07 修复 issue #213,即
SELECT * FROM tbl这类无 WHERE 条件的请求给出全表扫描风险提示,其Content还建议SELECT COUNT(*)类请求可改用SHOW TABLE STATUS或EXPLAIN估算(rules.go#L296-L303); - ARG.008(OR 查询索引列时请尽量使用 IN 谓词):2019-04 修复
col = 1 OR col IS NULL的边界情况; - ARG.009 / RuleSpaceWithQuote(引号中字符串首尾包含空格):2019-04 增加列表范围检查,防止误报;
- CLA.009(ORDER BY 条件为表达式):2018-11 修复大小写不敏感的正则匹配(issue #104);
- "always true where condition"(#38):即对
WHERE 1=1这类恒真条件的检查; - 索引列比较大小写敏感 bug(2019-04):修复索引建议中对列名大小写处理不一致的问题。
这些修复记录表明,每一条规则不仅有规则定义与检测函数,还配有对应的测试用例(见 advisor/heuristic_test.go 与 advisor/testdata/ 下的 golden 文件)。
四、索引优化建议(Index Advisor)的演进
4.1 两种模式:基于元数据 vs 无环境信息
2018-04 同时落地了"基于数据库环境信息给予索引优化建议"与"不依赖数据库元信息的简单索引优化建议"两条路径,对应 advisor/index.go 中IndexAdvisor在不同 DSN 配置下的工作方式。前者需要连接 MySQL 获取表结构、索引与散粒度(cardinality)信息;后者在没有环境信息时仅基于 SQL 结构给出建议。min-cardinality(索引列散粒度最低阈值,范围 0.0~100.0)就是为此引入的配置。
4.2 索引建议的迭代记录
- 2018-05:支持前缀索引;索引去重;
- 2018-06:索引优化建议支持对约束的检查;
- 2018-07:提供索引重复检查小工具,即
-report-type duplicate-key-checker(见 common/config.go 中ReportTypes定义),对online-dsn指定库进行重复索引检查,其实现位于 advisor/index.go; - 2019-05:修复 #205 create index 重写错误、修复 PRIMARY KEY 追加到多列复合索引(2019-07)、修复索引列比较大小写敏感 bug(2019-04);
- 索引建议的产出形式:
IndexAdvisor会生成形如alter table \db`.`tbl` add index ...` 的 DDL 建议(见 advisor/index.go),并附带散粒度百分比等依据信息。
索引相关配置在 common/config.go 中成体系:max-index-cols-count(复合索引最大列数,命令行解析时上限强制为 16)、max-index-bytes-percolumn(默认 767)、max-index-bytes(默认 3072)、max-index-count(单表最大索引数,默认 10)、index-prefix(默认idx_)、unique-key-prefix(默认uk_)、allow-drop-index(是否允许输出删除重复索引的建议)等。
五、测试环境与数据采样:安全执行 SQL 的关键机制
5.1 测试环境生命周期管理
soar 采用"线上 + 测试"双环境模型。2018-11 引入-cleanup-test-database参数,用于"清理残余的测试数据库(程序异常退出或未开启 drop-test-temporary)",对应 issue #48;2019-02 修复 #196"错误的 ip/password 会导致 soar -check-config 挂起"。cleanup-test-database的执行入口在 cmd/soar/soar.go#L60-L64:当该参数开启时,程序连接vEnv并调用CleanupTestDatabase()后直接退出。
5.2 数据采样的演进
- 2018-05:添加数据采样功能,并通过
sampling-statistic-target控制采样因子; - 2018-06:修复数据采样中 NULL 值处理不正确的问题(issue #58 在 2018-12 再次被提及,说明该问题经过多轮打磨);
- 2018-12:fix #58 "sampling not deal with NULL able string"。
采样与profiling、trace联动:在开启数据采样的情况下,可在测试环境执行 Profile 与 Trace(common/config.go),对应 database/profiling.go 与 database/trace.go。
5.3 测试数据库
2019-01 新增测试数据库world_x,与既有 sakila 等标准示例库一起作为测试用例的载体,用于验证索引建议与采样逻辑(可从 test/ 目录的 bats 测试与 golden 文件看出其用法)。
六、Explain 分析能力:从基础输出到兼容性打磨
Explain 是 soar 的另一大支柱,其演进记录如下:
- 2018-03:支持 MySQL Explain 信息输出;
- 2018-05/06:Explain 支持
last_query_cost,对应show-last-query-cost配置与max-query-cost警告阈值; - 2019-05:为 explain 查询添加
max_execution_timehint,防止超长查询拖垮测试环境; - 2018-12:fix #172 兼容 MySQL 5.1(其 EXPLAIN 结果没有
Index_Comment列)、fix explain 多行结果错误; - 2019-04:修复 explain 结果多行时的处理错误。
Explain 检查项在配置中自成体系(common/config.go):explain-type(traditional/extended/partitions)、explain-format(json/traditional)、explain-warn-select-type、explain-warn-access-type(默认警告ALL全表扫描)、explain-max-keys、explain-max-rows(默认 10000)、explain-warn-extra(默认警告Using temporary与Using filesort)、explain-warn-scalability(复杂度警告名单,支持 O(n)/O(log n)/O(1)/O(?))等。这些检查在 database/explain.go 中解析执行计划后,由 advisor/explainer.go 结合配置阈值生成建议。
七、报告输出与辅助工具:report-type 家族的扩充
7.1 输出格式的演进
CHANGES.md 记录了报告类型的逐步扩充:
- 2018-04:引入配置文件与日志模块;
- 2018-09:新增
lint报告类型,"支持 Vim Plugin 优化建议输出"(对应 doc/editor_plugin.md 中描述的编辑器插件场景); - 2018-11:新增
chardet报告类型,用于猜测输入 SQL 的字符集;新增-cleanup-test-database、-check-config参数; - 2018-12:新增
ast-json、tiast-json报告类型,将 Vitess AST 与 TiDB AST 以 JSON 输出(主要用于测试); - 2019-02:新增
query-type报告类型,输出 SQL 语句的请求类型; - 2019-04:修复
-report-type=json未输出 score 的问题(issue #199)与 JSON 结果格式问题(issue #98)。
完整的报告类型清单定义在 common/config.go#L847-L957 的ReportTypes中,包括lint、markdown、rewrite、ast、ast-json、tiast、tiast-json、tables、query-type、fingerprint、md2html、explain-digest、duplicate-key-checker、html、json、tokenize、compress、pretty、remove-comment、chardet,可通过-list-report-types查看(common/config.go#L959-L975)。
7.2 输出细节的修复
- 2019-01:新增
JSONFind函数支持 JSON 迭代,修复 #173WHERE col = col = '' and col1 = 'xx'场景;修复 #178 JSON 数据类型仅支持 utf8mb4 的问题; - 2019-07:fingerprint verbose 模式增加 id 输出;
- 2019-01:修复 #184 表状态字段数据类型溢出、#110 评审前去除 BOM、#112 多行注释导致行计数错误(lint 报告类型)。
7.3 辅助小工具
remove-comment(去除 SQL 注释,支持单行多行)与compress(SQL 压缩)、pretty(SQL 美化)这类报告类型本质上都是"单功能小工具",2018-07 也明确提到"提供 remove-comment 小工具"。它们直接复用ast与database包中RemoveSQLComments、Compress、Pretty等函数。
八、SQL 切分、解析与重写:SplitStatement 与 Rewrite 规则的演进
8.1 SplitStatement 的多轮修复
SQL 切分是处理多语句输入的入口(cmd/soar/soar.go#L116 调用ast.SplitStatement):
- 2018-10:修复多语句 EOF bug(#66);
- 2018-11:修复单行注释位于多行 SQL 中的切分问题(#116);修复多行注释导致
-report-type=lint行计数错误(#112);修复单行注释检查前未去空格(#120);RemoveSQLComment修复 trim space(#121); - 2019-01:SplitStatement 支持优化器 hint
/*+xxx */。
8.2 Pretty 与 Tokenizer
- 2018-10:修复 pretty 函数挂起问题(#47);
- 2018-11:修复 pretty 导致语法错误(#146);
- 2019-04:修复多类型引号混用时的 tokenize bug;
- 2019-01:修复 #173 中
WHERE col = col = ''的 JSONFind 场景。
8.3 SQL 重写规则
重写功能由-rewrite-rules指定、以-report-type rewrite输出。默认启用的重写规则定义在 common/config.go#L210-L219:delimiter(分隔符标准化)、orderbynull(GROUP BY 无谓排序追加 ORDER BY NULL)、groupbyconst(去除常量 GROUP BY)、dmlorderby(无意义的 ORDER BY)、having(HAVING 改写)、star2columns(SELECT * 展开为显式列)、insertcolumns(INSERT 显式列名)、distinctstar(去除无意义 DISTINCT *)。规则清单通过-list-rewrite-rules输出,实现位于 ast/rewrite.go。2019-05 修复的"create index rewrite error"(#205)即属于 DDL 重写范畴。
九、配置、底层依赖与工程化演进
9.1 配置体系的成型
2018-04 引入配置文件。加载逻辑在 common/config.go#L781-L837:指定-config时只读该文件;未指定时按/etc/soar.yaml→BaseDir/etc/soar.yaml→BaseDir/soar.yaml顺序查找。2018-11 修复了-config参数加载文件错误的问题。仓库自带的示例配置见 etc/soar.yaml。配置项通过-print-config输出(密码默认脱敏为********,见 common/config.go#L543-L552)。
9.2 底层依赖的替换
- 2018-12:将 MySQL 驱动从 mymysql 替换为 go-sql-driver。该替换带来两个直接收益:DSN 解析能力升级(common/config.go#L445-L453 中
ParseDSN优先使用 go-sql-driver 的解析,失败时回退旧版parseDSN),以及命令行 DSN 参数支持在密码中包含@、/、:等特殊字符; - 2019-02:新增 go.mod 以支持 Go 1.11 的模块化构建;
- 2018-11:将全部第三方库纳入 vendor,保证可复现构建。
9.3 安全与健壮性
- 2018-12:新增字符串转义函数用于安全防护;
usage()输出中自动对密码做:********@脱敏(common/config.go#L477-L541); - 2018-11:放弃 stdin 终端交互模式(该模式易被误认为程序挂起);修复 #141 查询在 MySQL 执行失败时输出为空的问题;
- 2019-01:修复 #184 表状态字段数据类型溢出。
9.4 测试与 CI 工程化
- 2018-06:添加 main_test 全功能回归测试;利用 docker 临时容器进行 daily 测试;
- 2018-08:Makefile 添加依赖检查、优化逻辑;引入 retool 管理依赖工具;优化 gometalinter 性能,引入新的代码质量检测工具;
- 2019-01:引入 bats、query.bats、env.bats、other.bats 与 test_helper.bash 即为其产物,对应测试输出见
test/fixture/下的 golden 文件; - 2018-10:使用 Travis 做 CI;修复 Go 1.8 默认 GOPATH 兼容问题(#5)。
9.5 开源历程
CHANGES.md 明确记录了两个里程碑:2018-09-21 Gdevops 首次对外进行技术分享宣传,2018-10-20 开源先锋日(OSCAR)对外正式开源发布代码。2018-08/09 期间"更新整理项目文档、开源准备""补充文档、添加项目 LOGO"等条目,说明开源前做了系统的文档化工作。
十、小结:从变更日志读出的工程方法论
回看 CHANGES.md,可以提炼出 soar 在 18 个月演进中坚持的三条工程原则:
- 规则质量靠边界测试驱动:几乎每条规则修复都对应具体 issue 与测试用例,规则函数、规则定义、测试用例三者在仓库中一一对应(advisor/rules.go ↔ advisor/heuristic.go ↔ advisor/heuristic_test.go);
- 兼容性优先:从 MySQL 5.1(无 Index_Comment 列)到 MySQL 8.0(驱动升级、JSON 类型),从 Go 1.8 到 Go 1.11 模块化,持续处理版本差异;
- 安全内建:字符串转义、DSN 密码脱敏、注入函数检测(SEC.004)、高危操作提醒(SEC.001~003),使 soar 不仅是性能工具,也是 SQL 质量与安全的守门员。
对于希望深入阅读源码的读者,建议按如下路径继续探索:先读 cmd/soar/soar.go 了解主流程,再分别进入 advisor/rules.go(规则全集)、advisor/index.go(索引建议与隐式转换检测)、common/config.go(全部配置项与默认值)、database/explain.go(执行计划解析)。如果你想验证某一版本的修复行为,test/fixture/下的 golden 文件是最直接的回归证据。
注:本文所述能力与修复均以 CHANGES.md 收录的时间范围(2018-03 至 2019-08)及当前仓库源码为准,版本演进以仓库实际内容为限。
- 开发工具
- 数据库
【免费下载链接】soar
SQL Optimizer And Rewriter
相关推荐
SOAR 安装指南:下载发布二进制、从源码构建与快速验证(SQL Optimizer And Rewriter)
SOAR 安装指南:下载发布二进制、从源码构建与快速验证(SQL Optimizer And Rewriter) 本篇指南完整讲解 SQL 优化与重写工具 SO
开发工具数据库SOAR:小米开源的 SQL 优化与改写工具(SQL Optimizer And Rewriter)实战指南
SOAR:小米开源的 SQL 优化与改写工具(SQL Optimizer And Rewriter)实战指南 SOAR(SQL Optimizer And Re
开发工具数据库终极文档下载工具指南:一键免费下载30+文库平台的完整教程
终极文档下载工具指南:一键免费下载30+文库平台的完整教程 还在为百度文库的登录验证烦恼吗?还在为道客巴巴的广告弹窗头疼吗?kill doc文档下载工具就是你需
开发工具数据库
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考