在做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
虽然方法还是比较笨拙和效率低下,但是基本能够满足要求.
我想把in 里的多个值变成问号,如何实现?