资讯详情

资讯详情

Archery 使用手册:SQL 审核工单、回滚与 binlog 排查实战

简介《archery使用手册》是一份面向SQL审核、查询平台使用者和MySQL运维人员的实操文档围绕Archery的审核规则、工单流程、SQL优化与实例管理展开适合开发、测试及DBA在数据库规范落地和日常排障中参考。压缩包共1个doc文件大小约1.2MB内容按功能详解与实践案例组织便于集中查阅。手册具体梳理SQL语法与规范审核、高危语句驳回、定时或立即执行及回滚SQL也覆盖执行计划分析、慢SQL统计、binlog清理、会话与事务终止、锁信息排查、账号授权和动态参数配置PTArchiver、Binlog2SQL、SchemaSync等插件的用途与操作示例亦有涉及。已有1479人学习可作为快速熟悉Archery功能边界、对照实践流程与查漏补缺的参考资料。1. Archery 不是只做审核一次误更新之后我重新读了这份手册凌晨收到磁盘告警登上去发现一条没走任何审核的 UPDATE 打在大表上备份是有的binlog 也在可真要从里面捞出一句正确的回滚语句团队里没人敢拍胸脯。这种翻车现场我见过不止一次。Archery 使用手册这份材料要解决的就是这条链路上的断点它把 SQL 审核、工单执行、回滚语句生成、会话与锁的排查、binlog 解析、表结构比对串成一个闭环让每次变更留审核记录让每句 DML 都有后悔药。它面向的是每天要碰库的人研发提工单、测试做环境验证、DBA 处置慢查询和阻塞。下面按我实际拆过一遍的顺序把流程、参数和坑位摊开。2. SQL 审核工单怎么走从提交检测到回滚 SQL 落盘很多人把审核理解成提交前点一下检测按钮实际用下来会发现真正的价值在于规则前置和回滚兜底这两头。审核只是中间一段前面要有可执行的规范后面要有能验证的回滚。这一章按规则、环境、操作、回滚四段拆。2.1 审核规则先立住主键、注释、高危语句三条硬线Archery 的审核链路是先把提交的 SQL 解析成语法树再逐条套自定义规则返回按等级分类的结果error 级直接阻断提交warn 级只提示不拦。所以规则配得好不好决定了这个平台是帮你把关还是变成走流程的橡皮图章。我一般会把硬线压到三条建表必须有主键、表和列必须有注释、高危语句自动驳回。第一条关系到后续数据订正和归档能不能定位到行没主键的表在 pt-archiver 归档时几乎没法安全分批第二条关系到后来人读不读得懂这张表尤其是字段上百的宽表第三条是保命的无 where 的 update/delete、drop table、truncate 这类语句一旦放过后面所有流程都白搭。先看一条能顺利过检的建表语句-- 提交前自己先过一遍主键、注释、字符集、索引命名都在 CREATE TABLE order_flow ( id bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 主键, order_no varchar(32) NOT NULL COMMENT 订单号, amount decimal(12,2) NOT NULL DEFAULT 0.00 COMMENT 金额, created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id), KEY idx_order_no (order_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单流水表;再看一条大概率被 error 拦下的-- 缺主键、表和列都没有注释规范类规则会逐条报出来 CREATE TABLE order_flow_bak ( order_no varchar(32) NOT NULL, amount decimal(12,2) );这两段的差别不在语法语法都合法。差别在解析器把 AST 拆开后能提取到的元信息有没有 primary key 节点、comment 属性是不是空、字段类型有没有超长、字符集是不是统一。参数上要留意规则等级同一条规则在不同实例上可以配成 error 或 warn比如历史库的存量表注释缺失较多一刀切成 error 会让所有变更都卡住这种库我一般先配 warn 跑两周把存量问题清完再收紧。规则项判定依据平台处置建议建表无主键AST 中缺少 PRIMARY KEY 定义error阻断提交所有新表强制表/列无注释comment 属性为空error 或 warn新库 error存量库先 warn高危 DML无 where 的 update/delete自动驳回一律 error不给例外字符集不一致表字符集与库默认不同warn统一 utf8mb4索引命名索引名不匹配约定前缀warn便于后期排查规则配完还要有人维护。常见做法是每季度拉一次被驳回的工单看看哪些规则误伤率高、哪些规则从来没人触发前者放宽后者说明开发已经养成习惯或者规则本身失效该删就删。2.2 开发环境与测试环境的两套流转逻辑同一套平台开发和测试两条流程的发起人、审核链、执行人都不一样弄混了最容易出现工单提错环境的低级问题。开发环境的链路是研发工程师发起 → 项目经理审核 → 最后一级通过后选择立即执行或定时执行。这条链多一道业务负责人的确认因为开发库往往是多人共用一次表结构变更可能影响同库的其他模块。测试环境的链路是测试同事从 git 上取开发已提交的 SQL 文件 → 在测试环境发起审核 → 测试同事自己审核并执行。发起和审核是同一个人看着像没审核其实是把把关点前移到了 SQL 检测那一步检测不过就提交不了提交了才轮到自己点通过。维度开发环境测试环境发起人研发工程师测试工程师SQL 来源本地开发整理git 上开发提交的文件审核链项目经理测试自己审核执行执行时机立即或定时立即为主主要风险影响多人共用库自审自执行跳过检测测试环境这条链最容易出的问题是测试同学拿到文件直接点提交、跳过 SQL 检测。平台的检测是提交前的独立动作不是提交时自动跑的漏点一次等于规则全部失效。我习惯在流程里加一条约定任何环境提交前必须先点检测检测结果截图跟工单一起留档。2.3 提交、检测、审批、执行四步实操把一次工单从头走到尾动作其实只有四步但每一步都有容易漏的细节。第一步准备 SQL 文件。文件名带上日期、库名、变更类型语句之间用分号分隔避免一个文件里混着 DDL 和 DML 却没标注。文件编码统一 UTF-8中文注释才不会在解析时变成乱码导致误判。第二步发起工单。选实例、选库、上传文件或直接粘贴填变更说明。点SQL 检测后看结果出现 error 就必须改 SQL 重新提交warn 可以带着说明继续。检测通过再点SQL 提交这时工单才真正进入审核队列。第三步审批。审核人登录后点右上角通知按钮看待办逐条看 SQL 和检测结果。这一步别只看有没有 error还要看变更窗口大表加索引这类操作即使语句合规也可能在业务高峰把 IO 打满。最后一级审核通过后选择立即执行或定时执行。定时执行的价值就在这里把变更压到低峰窗口不用人半夜守着点按钮。第四步执行后验证。执行成功不等于变更正确尤其是 DML 类工单要回查影响行数和数据分布。提交前我会在本地先跑一遍自检省得来回改-- 1. 找出没有主键的表返回结果为空才放心 SELECT t.table_schema, t.table_name FROM information_schema.tables t LEFT JOIN information_schema.statistics s ON s.table_schema t.table_schema AND s.table_name t.table_name AND s.index_name PRIMARY WHERE t.table_schema baidd AND t.table_type BASE TABLE AND s.index_name IS NULL; -- 2. 找出缺列注释的字段 SELECT table_name, column_name, column_type FROM information_schema.columns WHERE table_schema baidd AND (column_comment OR column_comment IS NULL); -- 3. 看表体量决定要不要改成定时执行 SELECT table_name, table_rows, ROUND(data_length / 1024 / 1024, 2) AS data_mb FROM information_schema.tables WHERE table_schema baidd ORDER BY data_length DESC LIMIT 10;第一段用 left join 反查 statistics 里没有 PRIMARY 索引的表注意要把 table_type 限定成 BASE TABLE否则视图会被误报。第二段直接扫 columns 的 comment 字段返回的行就是审核时会被标出来的列。第三段看表体量和数据量data_mb 超过一定阈值我一般按 5GB 划线的变更就不要选立即执行了走定时。2.4 回滚 SQL 的生成与验证工单执行完之后页面上可以查看回滚 SQL和下载回滚 SQL。生成逻辑是把原语句按类型反向推导insert 对应 delete、delete 对应 insert、update 用原值反写 where 条件。这一步是整条链路里最像后悔药的部分但它的边界必须说清楚。DML 能回滚DDL 只能回滚结构、回滚不了数据。drop column 生成的回滚语句是 alter table add column列加回来了里面的值没了。truncate 更是连结构都不保留。所以看到工单里有 DDL 时回滚 SQL 只能当结构参考真正的兜底还是执行前的备份。回滚 SQL 下载下来别急着存网盘。我一般会在影子库先执行一遍拿一份同结构的空库把回滚语句跑通确认语法没问题、where 条件能命中预期行数、没有漏掉 limit。这一步花十分钟能挡住后面几小时的排查。原操作回滚语句形态数据能否恢复insertdelete ... where 主键能updateupdate ... set 原值 where 主键能deleteinsert ... values 原行能alter table add columnalter table drop column仅结构alter table drop columnalter table add column数据丢失truncate / drop无有效回滚不可恢复提示回滚 SQL 生成后要检查 where 条件是否带上了完整主键。缺主键的 update 生成的回滚语句会按原 where 条件反写一旦原条件是范围匹配回滚可能波及更多行。3. SQL 优化与慢日志执行计划里那几个字段到底怎么看审核管的是能不能执行优化管的是执行得快不快。这两件事在 Archery 里是两个入口但排查思路是连着的慢日志告诉你哪条 SQL 慢SQL 分析告诉你为什么慢。3.1 SQL 分析入口与优化建议的取舍在 SQL 优化页面贴入语句平台会返回执行计划和优化建议。拿手册里的例子SELECT * FROM baidd.emp WHERE enamedan_1;分析结果会提示把select *改成具体字段改完再分析就变成 OK。为什么select *在这类规则里被判问题值得说清楚。一是覆盖索引失效本来ename上的索引能直接返回结果带*就得回表取整行二是宽表传输成本高几十个字段全部拉回客户端网络和内存都要付代价三是表结构变更后*的返回列会跟着变依赖固定列序的代码容易出问题。但优化建议不能照单全收。平台给的索引建议有时会和你已有的索引重复或者建议的字段区分度极低比如性别、状态位建了也用不上反而拖慢写入。我的判断顺序是先看执行计划里 type 是不是 ALL再看 rows 估算行数最后才看建议要不要采纳。-- 分析前先确认表上有哪些索引避免重复建 SHOW INDEX FROM baidd.emp; -- 看语句实际走了哪个索引 EXPLAIN SELECT id, ename, dept_no FROM baidd.emp WHERE ename dan_1;第一段返回索引名、列序、基数基数Cardinality越低说明这列区分度越差。第二段把*换成具体字段后再 explain对比 key 列有没有变化这是验证优化是否生效最直接的办法。3.2 执行计划字段解读执行计划里字段不少日常排查真正需要盯的就几个。字段含义关注点type访问类型ALL 全表扫描要处理index 次之range/ref/eq_ref 可接受possible_keys可能用到的索引为空说明压根没索引可用key实际使用的索引与 possible_keys 不一致时要看为什么没选中key_len索引使用长度比预期短说明联合索引只用了前几列rows预估扫描行数数量级偏大就要考虑改写或加索引filtered过滤后剩余比例很低说明 where 条件没被索引覆盖Extra附加信息Using filesort、Using temporary 是需要优化的信号type 从差到好的顺序大致是 ALL → index → range → ref → eq_ref → const。看到 ALL 不一定要立刻加索引小表全扫可能比走索引还快rows 只有几百行的表可以放一放。真正的血泪经验是 key_len联合索引 (a,b,c)如果 key_len 只等于 a 的长度说明 b 和 c 没用上常见原因是查询条件里跳过了 b 直接用了 c。Extra 里的 Using filesort 表示排序没走索引数据量大时会写临时文件Using temporary 表示用了临时表常见于 group by 和 distinct。这两个信号同时出现基本可以判定这条 SQL 需要改写。3.3 慢日志统计与索引确认慢 SQL 页面能看到慢语句列表和统计信息。统计维度一般包括执行次数、平均耗时、最大耗时、扫描行数。排序方式很关键按总耗时排找出来的是高频低耗的语句优化收益大按单次最大耗时排找出来的是偶发的重查询往往是某个报表或者导出任务。慢日志本身是采样受 long_query_time 阈值控制低于阈值的语句不会记录。所以看到没有慢 SQL不等于没有问题可能只是阈值设得太宽。我一般把阈值压到 1 秒先跑一周看整体分布再决定要不要放宽。-- 按平均耗时排序找出最该优先处理的语句 SELECT digest_text, count_star, ROUND(avg_timer_wait / 1e12, 3) AS avg_sec, ROUND(max_timer_wait / 1e12, 3) AS max_sec, sum_rows_examined FROM performance_schema.events_statements_summary_by_digest WHERE schema_name baidd ORDER BY avg_timer_wait DESC LIMIT 20;这段查的是 statements summary 表digest_text 是归一化后的语句模板参数被替换成 ?所以同一类语句会聚合成一行。avg_timer_wait 单位是皮秒除以 1e12 换成秒。sum_rows_examined 是累计扫描行数这个值除以 count_star 得到的平均扫描行数比耗时更能反映索引是否合理——平均扫描几万行才返回几条记录的语句优先处理。拿到慢语句后回到 SQL 分析页面贴进去看执行计划两步串起来才算闭环。只优化不加验证是另一个坑改完 SQL 要在测试环境用相近数据量跑一遍小数据量下执行计划可能选错索引上线后才暴露。4. 实例管理联动排查binlog、会话、事务与锁实例管理这一块默认只有管理员账号有权限权限收紧是对的因为这里的每个按钮都能直接影响线上。四个功能看似独立实际排查时经常要连着用会话列表看到阻塞转到锁信息确认阻塞方再看事务信息判断是不是长事务没提交。4.1 binlog 清理的顺序陷阱磁盘空间不足时清理 binlog 是最快的释放手段。在实例列表里选中某个 binlog平台会把这个文件以及它之前的所有 binlog 一起删除。注意这个之前是关键字如果你选中的是中间某个文件前面几个也会一起没。这个设计不是平台的问题是 MySQL 本身的机制决定的binlog 只能按顺序从最早的开始删。但操作时很容易误判成只删选中的这一个。我一般按三步走先确认从库同步到了哪个文件、确认没有延迟很大的从库还依赖旧文件、确认最近的备份对应的 binlog 起点在哪。-- 1. 从库同步到哪个文件、延迟多少 SHOW SLAVE STATUS\G -- 关注 Master_Log_File、Read_Master_Log_Pos、Seconds_Behind_Master -- 2. 当前正在写的 binlog SHOW MASTER STATUS; -- 3. 手工清理时对比平台操作一般在平台点命令行仅作核对 -- PURGE BINARY LOGS TO mysql-bin.000020;第一段在从库上执行Master_Log_File 表示从库已经读到主库的哪个文件Seconds_Behind_Master 是延迟秒数。清理前必须确认要删的文件都小于这个位置否则从库会报错中断。第二段在主库执行拿到当前文件号作为边界参考。第三段是 MySQL 原生命令只用来核对平台操作的范围对不对实际清理还是走平台因为平台会记录操作人和时间。注意清理 binlog 前确认最近一次全量备份的起始位置。如果备份对应的 binlog 被删掉这份备份就没法做基于时间点的恢复。4.2 会话管理必须先勾完整 INFO进程状态页面能看到当前正在执行的 SQL。右上角选择实例和 command 类型默认是 query只看查询类进程排查问题时切到 All把 Sleep、Binlog Dump 这些也带上才能看到全貌。这里有个反复踩的坑列表里的 INFO 列默认是截断的长 SQL 只显示前面一小段根本看不出问题。必须先勾上完整 INFO否则你会对着一句残缺的 SQL 排查半天。截断不是玄学是为了避免一次拉几百条长语句把页面拖死。定位到具体某条 SQL 造成阻塞后点终止会话就能 kill 掉。但终止前要确认两件事这条会话是不是在跑长事务、是不是已经执行了大半。一个跑了四十分钟的 alter table 被你 kill 掉回滚过程可能比原操作还久。4.3 事务与锁信息联合定位阻塞事务信息页面看当前运行的事务关键字段是 trx_mysql_thread_id它对应的就是进程状态里的 THREAD ID。锁信息页面看等待关系能看到等待事务的 SQL也就是被阻塞的那条和阻塞方的线程 id。手册里给了一个很干净的复现方式我在测试库照着跑过一遍-- 会话 A开事务并更新 id2 BEGIN; UPDATE baidd.t2 SET ename baidd WHERE id 2; -- 会话 B另一条连接执行会被阻塞 UPDATE baidd.t2 SET ename dan WHERE id 2;会话 A 执行完不提交会话 B 就会卡住。这时候在锁信息页面能看到等待事务的 SQL 是会话 B 那条 update阻塞方的线程 id 指向会话 A。处理方式有两种取决于业务确认会话 A 是忘了提交就直接按 trx_mysql_thread_id 在进程状态里搜到线程并终止如果会话 A 正在跑重要的批量更新就等它跑完贸然 kill 会触发回滚。排查顺序我习惯倒着来先看锁信息确认有没有等待再看事务信息确认阻塞事务开了多久最后去进程状态里定位线程。反过来做的话进程列表几百条很难一眼找出问题。-- 直接查锁等待关系与平台页面对照 SELECT r.trx_id AS waiting_trx, r.trx_mysql_thread_id AS waiting_thread, r.trx_query AS waiting_query, b.trx_id AS blocking_trx, b.trx_mysql_thread_id AS blocking_thread, b.trx_query AS blocking_query FROM information_schema.innodb_lock_waits w JOIN information_schema.innodb_trx b ON b.trx_id w.blocking_trx_id JOIN information_schema.innodb_trx r ON r.trx_id w.requesting_trx_id;这段查的是 innodb_lock_waits 和 innodb_trx 的关联waiting_thread 拿到后在平台进程页面搜就是那个要终止的会话。blocking_query 有时为空因为阻塞事务可能已经执行完语句处于 Sleep 状态这时候要看 blocking_trx 的开始时间和状态判断。4.4 账号管理与动态参数留痕账号管理支持图形化建号、授权、改密、删号。建完账号必须单独授权不会自动带上权限。授权时按最小权限给一个只读报表账号就不要给 INSERT。-- 平台授权背后的等价语句用于核对权限是否符合预期 GRANT SELECT, INSERT, UPDATE, DELETE ON baidd.* TO app_rw10.0.%; SHOW GRANTS FOR app_rw10.0.%;第一段是读写账号的典型授权库级粒度。第二段核对实际生效的权限重点看有没有意外的*.*或者 GRANT OPTION。平台操作完最好用这个语句复核一遍图形界面偶尔会有勾选遗漏。参数配置这一块能改实例的动态参数并记录修改历史。要区分动态参数和静态参数innodb_buffer_pool_size 在 5.7 之后支持在线调整但调整过程会占 IOmax_connections 可以直接改而像 innodb_log_file_size 这种改了要重启才生效的平台上改了不会立即体现容易误判成没生效。改完参数一定要在历史记录里留一句变更原因不然三个月后没人知道为什么这个值被调过。4.5 结构比对与归档入口实例管理之外还有两个常被忽略的能力。SchemaSync 用来读源库和目标库的表结构自动生成同步用的 DDL 和对应的回滚 SQL。它只比对表结构不比对数据所以拿它做上线前的结构核对很合适但别指望它发现数据不一致。PTArchiver 解决的是大表历史数据堆积。线上流水表只保留最近三个月更早的数据归档到历史库配成定时任务后不用人工干预。归档前务必确认表有主键否则分批删除没法定位行容易锁表。5. 常见问题与排查五条踩坑记录下面这几条是实际用下来反复出现的每条按现象、原因、解决写。第一条SQL 检测全绿执行时报错。现象是工单检测通过、审批通过点执行后返回字段不存在或者字符集不兼容。原因是检测阶段主要做语法解析和规范匹配不做执行环境校验SQL 里引用的表在目标库不存在、字段类型和值不匹配这类问题它发现不了。解决方式是在提交前先在目标库跑一次EXPLAIN或者SELECT ... LIMIT 0验证对象存在工单里附上验证结果。第二条回滚 SQL 执行了数据还是没回来。现象是 DDL 工单执行后发现问题下载回滚 SQL 跑完表结构恢复了但数据空了。原因是回滚语句只还原结构drop column、truncate 这类操作的数据在语句执行时就已经丢失。解决方式是所有含 DDL 的工单执行前做表级备份回滚 SQL 只当结构参考别当数据恢复手段。第三条清理 binlog 后从库报错中断。现象是磁盘告警处理完第二天发现从库同步停了报找不到 binlog 文件。原因是清理时选中的文件晚于从库已同步的位置前面被一起删掉了。解决方式是按 4.1 的顺序先查SHOW SLAVE STATUS确认 Master_Log_File 之后再操作已经出问题的从库需要重新做全量同步。第四条会话列表里看不到完整 SQL。现象是排查阻塞时INFO 列只有半句话看不出是哪个业务。原因是没勾完整 INFO页面默认做了截断。解决方式是进页面第一件事就勾上这个选项再选 command 类型为 All。这条踩过一次就会记住属于纯粹的界面习惯问题。第五条binlog2sql 解析不出回滚语句。现象是填入起始和结束位置后返回结果为空或者报格式错误。原因通常有两个实例的 binlog_format 不是 ROW或者选的位置区间内只有 DDL。前者需要确认参数配置后者是 binlog2sql 的固有限制DDL 无法生成回滚。解决方式是先在实例参数里确认binlog_formatROW再通过SHOW BINLOG EVENTS看区间内的事件类型只有 Query 事件DDL时不要指望回滚。6. 进阶用 binlog2sql 做一次可验证的数据回滚演练前面说的回滚 SQL 是平台根据原语句推的真正的兜底能力在 binlog2sql从 binlog 里把实际执行过的 SQL 解析出来再生成反向语句。这两者的差别在于前者依赖工单记录后者依赖磁盘上的 binlog即使有人绕过平台直接连库改数据也能捞回来。演练步骤我一般这么走。先确认 binlog_format 是 ROW这是解析的前提STATEMENT 格式拿不到行级变更。再通过SHOW MASTER STATUS和SHOW BINLOG EVENTS定位误操作落在哪个文件、哪个位置区间。然后进工具插件页面选实例、填起始文件和起止位置点获取 SQL。如果只是想确认改了什么这一步就够了要回滚就点 flashback 再获取一次平台会返回反向语句。文件大时用异步获取执行完会通知结果。命令行版本适合在演练环境先验证一遍# 解析原始 SQL看这段区间内到底执行了什么 python binlog2sql.py -h127.0.0.1 -P3306 -uuser -ppass \ -d baidd -t t2 \ --start-filemysql-bin.000009 --start-pos857 --stop-pos1183 # 生成回滚 SQL加 -B 参数输出的是反向语句 python binlog2sql.py -h127.0.0.1 -P3306 -uuser -ppass \ -d baidd -t t2 \ --start-filemysql-bin.000009 --start-pos857 --stop-pos1183 -B参数含义逐个数-d指定库名-t指定表名两个都可省略省略时解析全库全表但输出会很长--start-file和--start-pos是解析起点--stop-pos是终点位置号可以从SHOW BINLOG EVENTS IN mysql-bin.000009的结果里找-B是 flashback 开关输出 update 的反向 update、insert 的反向 delete。第一次跑建议先不加-B看清楚原始变更再决定。场景参数组合输出内容确认改了什么不加 -B原始 SQL生成回滚语句加 -B反向 DML只要 insert 部分加--only-dml --sql-type INSERT插入语句去掉主键生成加--no-primary-key无主键 insert回滚语句生成后不要直接往生产跑。我的做法是先导入影子库比对影响行数和主键范围确认无误再执行。DDL 的回滚别指望这个工具它只处理 DML。从那以后我每次做数据订正工单都强制走一遍定位 binlog 位置 → 解析原始 SQL → 生成回滚 → 影子库验证这四步哪怕只是改一行。多花十分钟换来的是出问题时能当场把数据摆回去而不是对着一堆备份文件干瞪眼。希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

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

立即咨询 →