数据库
首页 > 数据库> > SQL 解析原理和使用场景

SQL 解析原理和使用场景

作者:互联网

SQL解析是一项复杂的技术,一般都是由数据库厂商来掌握,由于这几年MySQL数据库中间件的兴起,需要支持读写分离、分库分表等功能,就必须从SQL中抽出表名、库名以及相关字段的值。因此像Java语言编写的Druid,Go语言编写的Kingshard等,都会对SQL进行部分解析

 

我们部门最近做的星云平台,内部有一个功能就是根据各种复杂的配置然后解析成可执行 SQL,这套解析框架是内部自己开发的,在配置相当复杂的时候生成的 SQL 也是非常的复杂,这个就可能出现 SQL 性能比较低下的问题,由于是异步全自动的取数过程,那么就考虑引入 SQL 解析优化引擎来内部动态优化生成的可执行 SQL

SQL解析与优化是属于编译器范畴,和C等其他语言的解析没有本质的区别。其中分为,词法分析、语法和语义分析、优化、执行代码生成。对应到MySQL的部分,如下图

词法分析

SQL解析由词法分析和语法/语义分析两个部分组成。词法分析主要是把输入转化成一个个Token。其中Token中包含Keyword(也称symbol)和非Keyword。例如,SQL语句 select username from userinfo,在分析之后,会得到4个Token,其中有2个Keyword,分别为select和from:

关键字非关键字关键字非关键字
selectusernamefromuserinfo

语法分析

语法分析就是生成语法树的过程。这是整个解析过程中最精华,最复杂的部分,不过这部分MySQL使用了Bison来完成。即使如此,如何设计合适的数据结构以及相关算法,去存储和遍历所有的信息,也是值得在这里研究的。

sql 语句:

select username from user where age > 20 and level > 5;

语法分析树:

上面的语法分析是 mysql 内部的 lexer 通过 c 语言完成的,其实也有很多语法编译框架用 java 写的语法解析框架,Druid 就是其中一个

Druid SQL Parser分三个模块:

- Parser

- AST

- Visitor

Parser

parser是将输入文本转换为ast(抽象语法树),parser有包括两个部分,Parser和Lexer,其中Lexer实现词法分析,Parser实现语法分析。

AST

AST是Abstract Syntax Tree的缩写,也就是抽象语法树。AST是parser输出的结果。这也是语法树的精髓了,sql解析,本质上就是把sql转为 ast语法树,拿到这个语法树后,我们就能做很多事了,遍历也好,加点,修改也好,都可以在ast上完成。

那么 ast 到底是什么东西?怎么去理解这个抽象语法树呢?

案例:4/(1+1)*2  这样一个数学公式

 通过多个condition,以及左右叶子节点,就能构建足够复杂的语法树。那么为什么需要这么构建呢,当我们语法很简单时,那么无所谓,直接匹配字符串,或者正则也行,但是当语法足够复杂时,简单的匹配字符串,正则就不够用了,你很难检测语法是否正确,而且想要在此基础上增加语法,也几乎很难做到。而ast则把这些字符串变成结构化的数据了,你可以精确地知道一段代码里面有哪些变量名,函数名,组合条件,参数等,你可以非常精准地处理,相对于字符串处理来说,遍历数据大大降低的处理难度。而ast也常常用在如IDE中错误提示、自动补全、编译器、语法翻译、重构、代码混淆压缩转换等。

visitor

Visitor是遍历AST的手段,是处理AST最方便的模式,Visitor是一个接口,有缺省什么都没做的实现VistorAdapter。

我们可以实现不同的Visitor来满足不同的需求,Druid内置提供了如下Visitor:

- OutputVisitor用来把AST输出为字符串

- WallVisitor 来分析SQL语意来防御SQL注入攻击

- ParameterizedOutputVisitor用来合并未参数化的SQL进行统计

- EvalVisitor 用来对SQL表达式求值

- ExportParameterVisitor用来提取SQL中的变量参数

- SchemaStatVisitor 用来统计SQL中使用的表、字段、过滤条件、排序表达式、分组表达式

SQL解析使用场景

整个 SQL 解析的精髓就是理解 AST 树,那么我们拿到解析后的 SQL 可以做哪些事情呢?业界目前常用的是慢 SQL 优化、SQL 特征分析

优化分析案例(where 条件如下):

  

特征分析案例:

select username from user where age > 20 and level > 5;

-- sql 的特征
select username from user where age > ? and level > ?;

业界著名的慢查询分析工具pt-query-digest,通过正则表达式实现这个功能但是这类处理办法Bug较多。接下来就介绍如何使用SQL解析,完成SQL特征的生成。

原始SQLpt-query-digest生成的特征SQL解析器生成的特征
select * from email_template2 where id = 1select * from mail_template? where id = ?select * from email_template2 where id = ?
REPLACE INTO a VALUES(‘INSERT INTO foo VALUES (1),(2)’)replace into a values(\‘insert into foo values(?+)replace into a values (?)

标签:场景,AST,语法,SQL,解析,where,select
来源: https://blog.csdn.net/wmq880204/article/details/122338118