线上在执行那么多的 SQL 语句, 如何根据 SQL 的特征进行归类, 方便统计一些执行信息?
0x00 SQL 特征计算方法
来看 SQL 的示例:
SELECT * FROM USERS WHERE id = 1;
select * from users where id = 2;
虽然两个语句返回的结果不一样,但特征都是:
- 从
USERS
表中查询所有的字段 - 条件是
id = ?
因此, 从特征上说, 上述两个 SQL 是一样的, 不一样的是参数, 当然还有大小写. 因此:
如果我们把 SQL 中的所有的参数替换成
?
并且将所有的大小写统一, 那么计算 SQL 语句的 md5 值就可以作为 SQL 的唯一特征, 也可以叫做 SQL 的 fingerprint
0x01 SQL 特征实现
技术实现原理也很简单, 简单来讲仅需两步:
- 解析 SQL, 获得 AST(抽象语法树)
- 通过实现 Vistor, 遍历整个 AST, 统一写法, 遇到参数直接换成
?
Java 程序员很有福气, 可以直接调用 alibaba 开源的 com.alibaba/druid
库的 com.alibaba.druid.sql.visitor.ParameterizedOutputVisitorUtils#parameterize(sql, dbType)
一句话搞定. 更庆幸的是, 人民的活雷锋 druid 库支持很多种 SQL, Oracle/MySQL/Hive 都不在话下.
0x02 SQL fingerprint 用处
识别了 SQL 的特征, 就可以把可以拿到的 SQL 全部计算特征并根据特征 GROUP BY.
MySQL Slow Query
最直接的使用场景就是把 MySQL 的 slow query log 拿出来计算特征, 这样就知道哪一类的 SQL 是执行瓶颈, 说不定发现一万条 Slow Query 其实是一个呢?
大名鼎鼎的 Percona 开源的 Percona Tookit 中的 pt-query-digest 其实就是这个思路, 推荐使用.
更进一步, 大家不都是把日志扔到 ELK 中吗? 更便捷的方式不就是把 MySQL Slow Query Log 解析后扔进 ELK, 并且添加一个 SQL_fingerprint 字段, 这样定位 Slow query 直接搜索一个 SQL_fingerprint
就可以知道类似的 Slow Query 大概是在什么时间段发生的频次了.
数据分析 SQL 识别
现在大家都嚷嚷大数据, 那么分析师会写很多的 SQL 用于数据查询. 如果你有一个 SQL
特征库:
- 识别禁止的 SQL 查询(比如非常低效率的 Hive SQL, 保护集群不被低效率的 SQL 查询拖垮)
- 识别错误的 SQL 查询, 例如一种写法的 SQL 是非常易错的, 可以发现有人执行类似的 SQL 后提醒用户查询错误
0x03 总结
识别了 SQL 的特征, 一定还有其他的应用场景有待挖掘, 祝玩儿的开心.
— EOF —