6 Mycat原理解析-EXPLAIN语句处理

  前面,我们已经讲过了Mycat如何判断sql类型,然后针对不同类型的sql就行不同的处理【Mycat原理解析-SQL语句的处理】,下面,我们来看看其中的explain语句,Mycat是怎么处理的。

  Mycat提供的EXPLAIN语句并不是用来查看执行计划的,而是用来查看路由结果的,如果要查询真正的执行计划,拿到路由结果里面的sql语句,到具体的实例上面查看就行了。例如,下面的sql语句,就被路由到了8个库。
这里写图片描述

下面,我们来看看这部分的源码ExplainHandler.java。

static {
    fields[0] = PacketUtil.getField("DATA_NODE",
            Fields.FIELD_TYPE_VAR_STRING);
    fields[1] = PacketUtil.getField("SQL", Fields.FIELD_TYPE_VAR_STRING);
}

public static void handle(String stmt, ServerConnection c, int offset) {
    //获取explain后面的sql
    stmt = stmt.substring(offset).trim();

    //获取路由结果
    RouteResultset rrs = getRouteResultset(c, stmt);
    if (rrs == null) {
        return;
    }
    ByteBuffer buffer = c.allocate();
    // 写入头部
    ResultSetHeaderPacket header = PacketUtil.getHeader(FIELD_COUNT);
    byte packetId = header.packetId;
    buffer = header.write(buffer, c,true);

    // 写入返回的字段【也就是示例中的第一行DATA_NODE、SQL】
    for (FieldPacket field : fields) {
        field.packetId = ++packetId;
        buffer = field.write(buffer, c,true);
    }

    // write eof
    EOFPacket eof = new EOFPacket();
    eof.packetId = ++packetId;
    buffer = eof.write(buffer, c,true);

    // 写入路由结果【也就是dataNode及对应的sql】
    RouteResultsetNode[] rrsn =  rrs.getNodes();
    for (RouteResultsetNode node : rrsn) {
        RowDataPacket row = getRow(node, c.getCharset());
        row.packetId = ++packetId;
        buffer = row.write(buffer, c,true);
    }

    // write last eof
    EOFPacket lastEof = new EOFPacket();
    lastEof.packetId = ++packetId;
    buffer = lastEof.write(buffer, c,true);

    // post write
    c.write(buffer);
}

private static RouteResultset getRouteResultset(ServerConnection c,
        String stmt) {
    String db = c.getSchema();
    int sqlType = ServerParse.parse(stmt) & 0xff;
    if (db == null) {
           db = SchemaUtil.detectDefaultDb(stmt, sqlType);
           if(db==null){
               c.writeErrMessage(ErrorCode.ER_NO_DB_ERROR, "No database selected");
               return null;
           }
    }
    //获取逻辑库对应的配置信息
    SchemaConfig schema = MycatServer.getInstance().getConfig()
            .getSchemas().get(db);
    //如果逻辑库不存在,返回错误信息
    if (schema == null) {
        c.writeErrMessage(ErrorCode.ER_BAD_DB_ERROR, "Unknown database '"+ db + "'");
        return null;
    }
    try {
        //不支持insert语句并且使用Mycat生成id的sql语句。这个很好理解,因为无法无法路由
        if(ServerParse.INSERT==sqlType&&isMycatSeq(stmt, schema){
            c.writeErrMessage(ErrorCode.ER_PARSE_ERROR, "insert sql using mycat seq,you must provide primaryKey value for explain");
            return null;
        }
        SystemConfig system = MycatServer.getInstance().getConfig().getSystem();
        //路由
        return MycatServer.getInstance().getRouterservice()
    .route(system,schema, sqlType, stmt, c.getCharset(), c);
    } catch (Exception e) {
        StringBuilder s = new StringBuilder();
        logger.warn(s.append(c).append(stmt).toString()+" error:"+ e);
        String msg = e.getMessage();
        c.writeErrMessage(ErrorCode.ER_PARSE_ERROR, msg == null ? e
                .getClass().getSimpleName() : msg);
        return null;
    }
}

有关路由部分的原理,会在后续的文章中进行剖析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值