• 【SQL解析】- Druid SQL Parser 02


    1. 简介

    SQL Parser是Druid的一个重要组成部分,Druid内置使用SQL Parser来实现防御SQL注入(WallFilter)、合并统计没有参数化的SQL(StatFilter的mergeSql)、SQL格式化、分库分表。

    1.1. 和Antlr生成Parser的区别

    和Antlr生成的SQL有很大不同的是,Druid SQL Parser性能非常好,可以用于生产环境直接对SQL进行分析处理。

    1.2. Druid SQL Parser的使用场景

    • MySql SQL全量统计
    • Hive/ODPS SQL执行安全审计
    • 分库分表SQL解析引擎
    • 数据库引擎的SQL Parser

    2. 各种语法支持

    Druid的sql parser是目前支持各种数据语法最完备的SQL Parser。目前对各种数据库的支持如下:

    这个是比较老的版本了, --新版本TODO补充
    在这里插入图片描述
    druid还缺省支持sql-92标准的语法,所以也部分支持其他数据库的sql语法。

    3. 性能

    Druid的SQL Parser是手工编写,性能非常好,目标就是在生产环境运行时使用的SQL Parser,性能比antlr、javacc之类工具生成的Parser快10倍甚至100倍以上。

    SELECT ID, NAME, AGE FROM USER WHERE ID = ?
    
    • 1

    这样的SQL,druid parser处理大约是600纳秒,也就是说单线程每秒可以处理1500万次以上。在1.1.3~1.1.4版本中,SQL Parser的性能有极大提升,完全可以适用于生产环境中对SQL进行处理。

    3.1. 测试代码看这里

    public class MySqlPerfTest extends TestCase {
        private String sql;
    
        protected void setUp() throws Exception {
            sql = "SELECT * FROM T";
            sql = "SELECT ID, NAME, AGE FROM USER WHERE ID = ?";
    
    //        sql = Utils.readFromResource("benchmark/sql/ob_sql.txt");
        }
    
        public void test_pert() throws Exception {
            for (int i = 0; i < 10; ++i) {
                perfMySql(sql);
            }
        }
    
        long perfMySql(String sql) {
            long startYGC = TestUtils.getYoungGC();
            long startYGCTime = TestUtils.getYoungGCTime();
            long startFGC = TestUtils.getFullGC();
    
            long startMillis = System.currentTimeMillis();
            for (int i = 0; i < 1000 * 1000; ++i) {
                execMySql(sql);
            }
            long millis = System.currentTimeMillis() - startMillis;
    
            long ygc = TestUtils.getYoungGC() - startYGC;
            long ygct = TestUtils.getYoungGCTime() - startYGCTime;
            long fgc = TestUtils.getFullGC() - startFGC;
    
            System.out.println("MySql\t" + millis + ", ygc " + ygc + ", ygct " + ygct + ", fgc " + fgc);
            return millis;
        }
    
        private String execMySql(String sql) {
            StringBuilder out = new StringBuilder();
            MySqlOutputVisitor visitor = new MySqlOutputVisitor(out);
            MySqlStatementParser parser = new MySqlStatementParser(sql);
            List statementList = parser.parseStatementList();
            // for (SQLStatement statement : statementList) {
            // statement.accept(visitor);
            // visitor.println();
            // }
            return out.toString();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    4. Druid SQL Parser的代码结构 (业内通用)

    Druid SQL Parser分三个模块(几乎所有的SQL解析器都是这三个模板设计):

    • Parser
    • AST
    • Visitor

    4.1 parser

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

    4.2. AST

    AST是Abstract Syntax Tree的缩写,也就是抽象语法树。AST是parser输出的结果。下面是获得抽象语法树的一个例子:

    final String dbType = JdbcConstants.MYSQL; // 可以是ORACLE、POSTGRESQL、SQLSERVER、ODPS等
    String sql = "select * from t";
    List stmtList = SQLUtils.parseStatements(sql, dbType);
    
    • 1
    • 2
    • 3

    Druid SQL AST介绍 https://github.com/alibaba/druid/wiki/Druid_SQL_AST

    4.3. Visitor

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

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

    • OutputVisitor用来把AST输出为字符串
    • WallVisitor 来分析SQL语意来防御SQL注入攻击
    • ParameterizedOutputVisitor用来合并未参数化的SQL进行统计
    • EvalVisitor 用来对SQL表达式求值
    • ExportParameterVisitor用来提取SQL中的变量参数
    • SchemaStatVisitor 用来统计SQL中使用的表、字段、过滤条件、排序表达式、分组表达式
    • SQL格式化 Druid内置了基于语义的SQL格式化功能

    4.4. 自定义Visitor

    每种方言的Visitor都有一个缺省的VisitorAdapter,使得编写自定义的Visitor更方便。 https://github.com/alibaba/druid/wiki/SQL_Parser_Demo_visitor

    4.5. 方言

    SQL-92、SQL-99等都是标准SQL,mysql/oracle/pg/sqlserver/odps等都是方言,也就是dialect。parser/ast/visitor都需要针对不同的方言进行特别处理。

    5. SchemaRepository

    Druid SQL Parser内置了一个SchemaRepository,在内存中缓存SQL Schema信息,用于SQL语义解析中的ColumnResolve等操作。 https://github.com/alibaba/druid/wiki/SQL_Schema_Repository

    6. SQL翻译

    可以基于Druid SQL Parser之上构造Oracle SQL到其他数据的SQL翻译。比如Aliyun提供的Oracle到MySql的SQL翻译功能,就是基于Druid基础上实现的。https://rainbow-expert.aliyun.com/sqltransform.htm

  • 相关阅读:
    file-storage-sdk项目开发中的踩坑记录
    菁染料CY7.5标记海藻酸钠|CY7.5-海藻酸钠|alginate-Cyanine7.5|CY7.5-peg-海藻酸钠alginate
    如何搭建一个vue项目
    探究MYSQL之索引
    selenium 元素定位
    SpringBoot电商进阶开发Day3
    【regex】正则表达式
    搭建 Kafka 需要做什么准备?
    07 【动态组件 组件注册】
    本地搭建vulfocus靶场&复现log4j2漏洞
  • 原文地址:https://blog.csdn.net/qq_31557939/article/details/126025649