mycat php,MyCat - 源代码篇(15)

数据库路由中间件MyCat - 源代码篇(15)

5. 路由模块

5.4 DDL语句路由

可以分为两步,整体源代码:

public static RouteResultset routeToDDLNode(RouteResultset rrs, int sqlType, String stmt,SchemaConfig schema) throws SQLSyntaxErrorException {

stmt = getFixedSql(stmt);

String tablename = "";

final String upStmt = stmt.toUpperCase();

if(upStmt.startsWith("CREATE")){

if (upStmt.contains("CREATE INDEX ")){

tablename = RouterUtil.getTableName(stmt, RouterUtil.getCreateIndexPos(upStmt, 0));

}else tablename = RouterUtil.getTableName(stmt, RouterUtil.getCreateTablePos(upStmt, 0));

}else if(upStmt.startsWith("DROP")){

if (upStmt.contains("DROP INDEX ")){

tablename = RouterUtil.getTableName(stmt, RouterUtil.getDropIndexPos(upStmt, 0));

}else tablename = RouterUtil.getTableName(stmt, RouterUtil.getDropTablePos(upStmt, 0));

}else if(upStmt.startsWith("ALTER")){

tablename = RouterUtil.getTableName(stmt, RouterUtil.getAlterTablePos(upStmt, 0));

}else if (upStmt.startsWith("TRUNCATE")){

tablename = RouterUtil.getTableName(stmt, RouterUtil.getTruncateTablePos(upStmt, 0));

}

tablename = tablename.toUpperCase();

if (schema.getTables().containsKey(tablename)){

if(ServerParse.DDL==sqlType){

List dataNodes = new ArrayList<>();

Map tables = schema.getTables();

TableConfig tc;

if (tables != null && (tc = tables.get(tablename)) != null) {

dataNodes = tc.getDataNodes();

}

Iterator iterator1 = dataNodes.iterator();

int nodeSize = dataNodes.size();

RouteResultsetNode[] nodes = new RouteResultsetNode[nodeSize];

for(int i=0;i

String name = iterator1.next();

nodes[i] = new RouteResultsetNode(name, sqlType, stmt);

}

rrs.setNodes(nodes);

}

return rrs;

}else if(schema.getDataNode()!=null){ //默认节点ddl

RouteResultsetNode[] nodes = new RouteResultsetNode[1];

nodes[0] = new RouteResultsetNode(schema.getDataNode(), sqlType, stmt);

rrs.setNodes(nodes);

return rrs;

}

//both tablename and defaultnode null

LOGGER.error("table not in schema----"+tablename);

throw new SQLSyntaxErrorException("op table not in schema----"+tablename);

}

首先,获取表名,步骤如下:

59b96a41963c43c5641de8c28dee565e.png

拿一个获取表名的函数举例:

/** * 获取语句中前关键字位置和占位个数表名位置 * *@param upStmt * 执行语句 *@param start * 开始位置 *@return int[]关键字位置和占位个数 *@author aStoneGod */

public static int[] getCreateIndexPos(String upStmt, int start) {

String token1 = "CREATE ";

String token2 = " INDEX ";

String token3 = " ON ";

int createInd = upStmt.indexOf(token1, start);

int idxInd = upStmt.indexOf(token2, start);

int onInd = upStmt.indexOf(token3, start);

// 既包含CREATE又包含INDEX,且CREATE关键字在INDEX关键字之前, 且包含ON...

if (createInd >= 0 && idxInd > 0 && idxInd > createInd && onInd > 0 && onInd > idxInd) {

return new int[] {onInd , token3.length() };

} else {

return new int[] { -1, token2.length() };// 不满足条件时,只关注第一个返回值为-1,第二个任意

}

}

然后,根据表名获取配置进行路由:

093deecac88425ddfc6702fd4bb27040.png

* 默认语句路由*

对于有默认节点的schema,且不是show, describe, select @@之类的语句,则路由到默认的节点上。

对于show, describe, select @@之类的语句,利用查询信息路由方法算出路由。

e0b236ee21f27f71cbcc173a5145a618.png

接下来,取一个举例,对于Show语句:

analyseShowSQL(schema, rrs, stmt)方法

a1f2a4da091457e62ab208841063a2f0.png

5.5 AST语义解析路由

首先我们看一下MySQL的SQL解析步骤(硬解析和软解析):

92d626219ddc20743edf014e39c28679.png

MyCat的机制,仿照MySQL的,可以总结为:

2bd47922f84165106ac6882396bb0ede.png

这里我们可以总结一个优化思路,就是通过仿照MySQL物理优化原理(定时更新表配置,报表信息),来做进一步MyCat查询的优化。

语义解析基本过程:

1.词法分析(一般抽象都叫Lexer):不同的关键词有不同的含义

select concat(id,'_',name),value from student where value>60 order by value

978bec6dd756701f485531f25a6c6091.png

词法分析的输出,就是一句带上词义的语句:

(select: Keyword) (concat: Keyword)((: LB)…… (from: keyword) (student: identifier)

2.语法分析:

分析关键词之间的联系,生成表达式(expression)

基本语法正确性判断(比如from这个keyword之后必须紧跟一个表名(就是一个identifier))

b0abdc61c131fc3650e5812c860cdb82.png

3.生成AST语意树(完整解析的statement)

d0749a4a849802da4b3e6e7e226293a2.png

根据MyCat权威指南,DruidParser比其他Parser快很多很多。

快在哪里呢?主要是抽象静态化的粒度,拿jsqlparser和druidparser对比。

这两个parser都遵从了上面的步骤,对于词(lexer),表达式(expression)和语句AST(statement)都有抽象。

但是对于语句AST(statement)的抽象, DruidParser做的粒度更细。如下图对于Alter语句的对比:

19cf7524898349af96de21b887788c2e.png

所以,不难推测为啥DruidParser快了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值