sql去参数格式化

在做mysql sql审计或者slowlog分析的时候,经常需要把sql中的参数替换成一个常量,分析sql schema,做hot  query或者slow log分析。对于OLTP业务,一个语句很少重复出现,因为参数(sepcification)时时刻刻都在发生变化,比如访问用户id,订单号,库存等数据。之前很多工具也实现了这个功能,比如pt-query-digest。
公司同事之前也做过这方面的工作,看了一下逻辑,正则表达式十几行。感觉过于繁琐,re本来就是一种很精练的表达。不多说,先看下我实现的逻辑。
                sql  = re.sub(“[‘\”].*?[‘\”]”,”‘S'”,sql)
                sql  = re.sub(“(?<=[\(\s=,])\d+(?=[\),\s;])”,”N”,sql)
1)把字符串内容替换成’S’。比如,’aaa’或者“1111”替换成’s’。
字符串替换不用多说,因为字符串的界定符比较明显,一般的是单引号说着双引号。
2)把数字替换成N。比如,id = 1 替换成 id = N。
数值替换比较复杂,因为通常没有固定的界定符,所以感觉比较复杂。
insert into t1 (`f1`,`f1`,`f1`) values(123,345,’v3′)
select * from `t1` where `f1` = v1;
update `a` set `f1` = v111 where f1 in ( 123,456, 789)
归纳可以发现:
数字前面的界定符有空格(\s), 正括号’(’,逗号’,’, 等号’=’。
数字后面的界定符有空格(\s), 反括号’)’,逗号’,’, 分号’;’
#!/bin/env python
import re

sql = "select * from redis where id = 123 and port in (6379 , 6382) and dns = 'vip.com'"
sql = re.sub("['\"].*?['\"]",'S',sql)
print sql
sql = re.sub("(?<=[,\(\s=])\d+(?=[,\)\s;])",'N',sql)
print sql

#select * from redis_dns where hostid = 123 and port in (6379 , 6382,6381) and dns = S
#select * from redis_dns where hostid = N and port in (N , N,N) and dns = S

虽然方法还是比较笨拙和效率低下,但是基本能够满足要求.
此条目发表在develop分类目录,贴了, 标签。将固定链接加入收藏夹。

sql去参数格式化》有 1 条评论

  1. Wu.Xu说:

    我想把in 里的多个值变成问号,如何实现?

发表评论

邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据