根据SQL提炼表信息

这是学习笔记的第 1958 篇文章

在MySQL慢日志通过pt工具解析后有一个小问题,那就是我们很难得到一个完整的table列表,即假设一条SQL语句很长,那么我们其实想知道这条SQL相关的表是哪几个,如果能够很清晰的提炼出来,那么我们要做后续的分析就会锦上添花。

显然这个工作是有一些复杂度的,大体想了下,有以下的一些难点:

  1. select语句如果是多个表关联,那么这个提取工作就会增加解析的复杂度
  2. insert语句如果是insert xxx select xxx from的形式,那么得到的相关表应该是两个以上
  3. 如果是replace,load等语句,解析规则需要自己定制,目前没有通用的方法
  4. 如果语句含有注释,换行等符号,需要甄别和过滤

所以这一块算是有一些实现难度的功能,我们可以简化下思路,可以把SQL语句先做下格式化,把回车,换行,注释等都统一处理下。

这样在一个基本规范的前提下,我们把SQL语句切分成多份,然后按照语句的规则来做匹配,比如对于select语句,我们的提炼逻辑是找到from和join关键字的位置,进行table的信息提取。

关于语句的格式化部分,可以使用re来实现,主要是做正则表达式的相关逻辑检查。

然后指定一个字典结构,根据自定义的SQL匹配规则进行信息补充,这样对于insert语句,我们可以灵活的匹配insert select from的场景。

如果有些表名重复,为了去重排序,我们可以使用set的数据结构。

整体的代码实现如下:

import re

def extract_table_name_from_sql(sql_str):

# remove the /* */ comments

q = re.sub(r"/\*[^*]*\*+(?:[^*/][^*]*\*+)*/", "", sql_str)

# remove whole line -- and # comments

lines = [line for line in q.splitlines() if not re.match("^\s*(--|#)", line)]

# remove trailing -- and # comments

q = " ".join([re.split("--|#", line)[0] for line in lines])

# split on blanks, parens and semicolons

tokens = re.split(r"[\s)(;]+", q)

# scan the tokens with user-defined logic to get table info list

result = set()

if tokens.__len__()>0:

sql_type = tokens[0]

else:

sql_type = "dummy"

#print sql_type

sql_type_map = {}

sql_type_map["select"] =["from", "join"]

sql_type_map["update"] =["update","from"]

sql_type_map["insert"] =["into","from","join"]

sql_type_map["delete"] =["from"]

sql_type_map["load"] =["table"]

sql_type_map["replace"] =["into"]

sql_type_map["alter"] =["table"]

for idx, token in enumerate(tokens):

if token.lower() in sql_type_map[sql_type.lower()]:

result.add(tokens[idx+1])

return ",".join(str(i) for i in list(result))

打个比方,我们使用如下的测试SQL,需要解析table列表:

sql8="insert into test select xxxx from aa join b where aaaaa"

print(extract_table_name_from_sql(sql8))

得到的结果如下:

test,aa,b

对于select,load,update等语句,都可以灵活的调整字典里的配置来实现。

本文分享自微信公众号 - 杨建荣的学习笔记(jianrong-notes)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-04-23

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券