慢 SQL 交给 AI 之前:先核对 MySQL 原生 DIGEST
把慢日志交给模型之前,先决定哪些语句应该归为一类。正则替换数字和字符串,看起来只差几行代码;一旦字符串里带注释符,这几行就可能先把SQL改坏。
MySQL 8.4的Statement Digests文档说明,摘要由解析器计算:归一化文本存入DIGEST_TEXT,摘要哈希存入DIGEST。它保留语句结构、替换字面量,适合做聚合,不应被叫作“完整匿名化”。
概念示意图,非控制台截图、跑分或真实事件记录。
一个不需要数据库就能检查的反例
下面的代码只用于暴露一种错误方法,绝不是另一个指纹解析器。SELECT的字符串里包含“--”;先用正则剥注释,会留下一个未闭合的引号。
import re sql = "SELECT id FROM orders WHERE note='-- not a comment';" broken = re.sub(r"--.*", "", sql) assert broken.endswith("note='") assert broken.count("'") == 1 print("original:", sql) print("broken:", broken) print("PASS counterexample: regex damaged a string literal")真实解析器需要同时理解引号、转义、注释、标识符和方言。MySQL对注释的具体语法还有自己的限制。把一个正则变成十个正则,通常只是让后续反例更费劲。
先用服务器自己认识的摘要
以下是MySQL 8.4的诊断查询,供已授权的测试实例使用。本轮环境没有MySQL服务,未执行这段SQL:
SELECT SCHEMA_NAME, DIGEST, DIGEST_TEXT, COUNT_STAR, SUM_TIMER_WAIT, SUM_ROWS_EXAMINED FROM performance_schema.events_statements_summary_by_digest WHERE DIGEST IS NOT NULL ORDER BY SUM_TIMER_WAIT DESC LIMIT 10;SUM_TIMER_WAIT的单位与展示方式要查对应版本文档,再做换算;不要直接把原始整数标成“毫秒”。按总耗时看高频负载是一个入口,不代表总耗时最高的指纹就是根因。锁等待、I/O和上游突发流量还需要各自证据。
DIGEST也有截断边界。max_digest_length限制归一化时采集的token长度,后半段不同的长SQL可能被聚成同类;Performance Schema自身复制的摘要文本还可能再次截断。仅看屏幕上相同的DIGEST_TEXT,不足以断言两条原始语句完全相同。
摘要、脱敏和AI输入是三件事
表名、列名会保留业务信息;QUERY_SAMPLE_TEXT还可能包含原始字面量。对外发送时,应先确定允许的数据范围,再决定是否提供原始样本,不能因为已经“算了摘要”就直接上传。
我更愿意给模型一份有出处的证据包:授权后的结构信息、摘要、次数、累计耗时、扫描量、采样时间与对应计划。模型输出必须写成“假设及验证方法”,不能把“可能缺索引”直接改成DDL执行指令。10月22日的Langfuse集成指南还提醒我们,工具输入输出会进入trace;日志出站和trace留存要一起检查。
本地只运行了正则反例,证明这个具体替换会损坏字符串。服务器摘要、统计采样和模型诊断未实测;没有“数小时降到数秒”的结论。
本文的本地检查仅覆盖明确列出的合成示例;外部研究与产品文档不作为本人性能实测。
复现命令:将Python反例保存为 fingerprint_counterexample.py,运行 python3 fingerprint_counterexample.py;本轮使用Python 3.9.6。