当前位置: 首页 > 科技观察

Cobar源码分析之AST

时间:2023-03-13 02:09:23 科技观察

本文转载自微信公众号《捉虫大师》,作者为捉虫大师。转载本文请联系捕虫大师公众号。背景CobarCobar是阿里巴巴开源的数据库中间件。我不会在这里详细介绍它。可以参考之前的文章?SQLSQL是关系型数据库中常用的一种领域语言(编程语言),方便对结构化数据进行管理。数据库在执行SQL时,首先对SQL进行词法分析、句法分析、语义分析,生成抽象语法树(AST),再由优化器处理生成执行计划,再由数据库执行。执行引擎。SQLParser将SQL解析成AST的解析器称为SQLParser。这种解析器通常有两种开发方式:工具自动生成优点:简单易实现缺点:性能较差,二次开发困难手动编写优点:性能好,代码清晰,易扩展缺点:对开发人员要求高,需要了解编译原理SQLParser也在Cobar中实现,从它的架构图可以看出它在Cobar中的位置:SQLParser后面是SQLRouter,由此可以推断出SQLParser解析出AST的目的是用于分库分表的路由功能。Cobar的SQLParser也经历了三个版本的迭代,本质都是性能方面的考虑:第一个版本:基于JavaCC生成的SQL解析器,性能较差,不便优化;第三版:基于LL(2)识别器的手写体。本文不过多介绍SQLParser。这篇文章仔细看了好几遍,附上一张总结脑图:https://github.com/lkxiaolou/reading/tree/main/xmindCobarAST中的SQLParserCobar将SQL解析成AST。为了直观感受,举个例子:selectid,typefromgoodsasgwheretypein(selecttypefromtype_configwherestatus=0)CobarSQLParser后,生成如下AST对象:这个AST根节点是select语句,然后每个属性都是叶子节点,而叶节点的属性进一步划分为叶节点。可能有点绕,需要从代码层面去感受。AST的节点定义如下。这里只有一个accept方法,就是遍历树的。我暂时不关心它。后面会讲到:publicinterfaceASTNode{voidaccept(SQLASTVisitorvisitor);}这个ASTNode的实现方式主要有以下几种:SQLStatement:SQL语句,比如Select、update、insert等语句在DMLSelectStatement中体现在上图中的表达式:and,or,comparison等语句体现在InExpression,ComparisonEqualsExpression,LiteralNumber,IdentifierTableReference:表相关语句体现在TableReferences,TableRefFactorandComparisonEqualsExpression以实现为例,其中1为左右比较表达式,2是判断符号,这里是“=”,3是计算表达式。如何实施evaluationInternal?其实,表达式结构化、穷尽化之后,这个问题就变得简单了。比如这里只需要取左右两个值,比较是否相等。AST的操作有了上面对AST的理解,接下来就是看AST的操作了。最基本的是遍历。要使用ASTNode的accept,需要实现SQLASTVisitor接口。这个SQLASTVisitor的定义如下:其实就是利用了java的多态性。各种ASTNode都定义了访问方法,不同的对象在遍历时对应不同的方法。例如,MySQLOutputASTVisitor可以遍历AST并将AST还原为SQL输出,就像这样:.toString());本次执行会输出SELECTid,typeFROMgoodsASGWHEREtypeIN(SELECTtypeFROMtype_configWHEREstatus=0)SQLParserDelegate.parse(sql)将其解析成DMLSelectStatement对象,其访问方法实现如下:@Overridepublicvoidaccept(SQLASTVisitorvisitor){visitor.visit(this);}再看一下MySQLOutputASTVisitor的visit(DMLSelectStatementnode)的实现:代码比较长,这里就不贴了。大致思路是直接将叶子节点按照格式存放在StringBuilder中。否则继续调用对应节点的accept继续遍历,这是一种深度遍历的思想。我们可以参考MySQLOutputASTVisitor编写一个满足我们需求的遍历器。AST对分库分表的应用Cobar利用AST获取表名、列名、比较值进行分库分表,这也是Cobar最重要的功能。除了SQL特征生成,我所知道的AST还可以为原始SQL生成SQL特征。例如,原始SQL是这样的:selectid,name,agefromuserasuwhereage>=20或selectid,name,ageFromuserasuwhereage>=30可以规范化为selectid,name,age来自userasuwhereage>=?对SQL慢查询或其他统计,SQL限流等非常有用。一个没有where条件的update或delete写在危险的SQL截取行。这时可以使用AST进行表达式计算,拦截没有where条件且where条件一直为真的SQL。最后,本文介绍了SQLAST的来源、结构、遍历原理和应用。相信看完文章后,你会对SQLAST有一个初步的了解。如果想深入了解,可以参考Cobar项目中的单元测试进行实际演示体验。.