常见使用语句
# 查看创建表帮助文档
> HELP CREATE TABLE;
# 查看 ALTER 进度状态
> SHOW ALTER TABLE COLUMN;
# 取消 ALTER 进度
> CANCEL ALTER TABLE COLUMN FROM table1
# 查看 ALTER 相关命令
> HELP ALTER TABLE
语法解析过程
Doris SQL 解析具体包括了五个步骤:词法分析,语法分析,生成单机逻辑计划,生成分布式逻辑计划,生成物理执行计划。
具体代码实现上包含以下五个步骤:Parse, Analyze, SinglePlan, DistributedPlan, Schedule。如下图所示:
解析执行过程
上图中未提及 Parse 过程,而该过程在 Doris 系统中语法解析分为三个阶段 jflex 词法分析、java cup parser 进行语法分析、生成抽象语法树(AST),AST 是种树状结构,将不同的查询语句 select, insert, show, set, alter table, create table 等经过 Parse 阶段后生成不同的数据结构(SelectStmt, InsertStmt, ShowStmt, SetStmt, AlterStmt, AlterTableStmt, CreateTableStmt 等)之后,根据语法规则进行逻辑处理即可。
因此整体流程下来即如下图:
一个简单的查询 SQL 在 Doris 的解析实现
注 使用 SqlParserUtils 实现 sql 解析过程,如下是 parse 结果实例:
String originStmt = "select username, sum(distinct link) from tbl_event_log group by username;";
SqlScanner input = new SqlScanner(new StringReader(originStmt), ctx.getSessionVariable().getSqlMode());
SqlParser parser = new SqlParser(input);
StatementBase statementBase = SqlParserUtils.getFirstStmt(parser);
注 实际解析过程在 org.apache.doris.qe.StmtExecutor 类进行解析,然后生成执行计划,实例如下:
String sql7 = "select * from db1.tbl1 where k1='a' and k4=1\n"
+ "except distinct\n"
+ "select * from db1.tbl1 where k1='a' and k4=1\n"
+ "except\n"
+ "select * from db1.tbl1 where k1='a' and k4=2\n"
+ "except\n"
+ "(select * from db1.tbl1 where k1='a' and k4=2)\n"
+ "order by 3 limit 3";
StmtExecutor stmtExecutor7 = new StmtExecutor(ctx, sql7);
stmtExecutor7.execute();
Planner planner7 = stmtExecutor7.planner();
List<PlanFragment> fragments7 = planner7.getFragments();
String plan7 = planner7.getExplainString(fragments7, new ExplainOptions(false, false));
注 Doris 解析过程如下所示:
# 在 org.apache.doris.qe.ConnectProcessor 类 handleQuery() 函数中获取 sql 内容,并将 sql 转化为 StatementBase 列表
// process COM_QUERY statement,
// 只有在与请求客户端交互出现问题时候才抛出异常
private void handleQuery() {
// ... 省略 ....
originStmt = new String(bytes, 1, ending, "UTF-8");
// ... 省略 ....
String sqlHash = DigestUtils.md5Hex(originStmt);
ctx.setSqlHash(sqlHash);
// 匹配数据 block 规则, 如果符合 block 规则则取消执行
Catalog.getCurrentCatalog().getSqlBlockRuleMgr().matchSql(originStmt, sqlHash, ctx.getQualifiedUser());
// ... 省略 ....
ctx.getAuditEventBuilder().reset();
ctx.getAuditEventBuilder()
.setTimestamp(System.currentTimeMillis())
.setClientIp(ctx.getMysqlChannel().getRemoteHostPortString())
.setUser(ctx.getQualifiedUser())
.setDb(ctx.getDatabase())
.setSqlHash(ctx.getSqlHash());
// execute this query.
StatementBase parsedStmt = null;
List<Pair<StatementBase, Data.PQueryStatistics>> auditInfoList = Lists.newArrayList();
boolean alreadyAddedToAuditInfoList = false;
try {
// 分析语法并将其转化为相应的 StatementBase 类
List<StatementBase> stmts = analyze(originStmt);
for (int i = 0; i < stmts.size(); ++i) {
alreadyAddedToAuditInfoList = false;
ctx.getState().reset();
if (i > 0) {
ctx.resetReturnRows();
}
parsedStmt = stmts.get(i);
parsedStmt.setOrigStmt(new OriginStatement(originStmt, i));
parsedStmt.setUserInfo(ctx.getCurrentUserIdentity());
// 将 StatementBase 类封装为 StmtExecutor 类
executor = new StmtExecutor(ctx, parsedStmt);
ctx.setExecutor(executor);
// 将 StatementBase 类解析为执行计划
executor.execute();
if (i != stmts.size() - 1) {
ctx.getState().serverStatus |= MysqlServerStatusFlag.SERVER_MORE_RESULTS_EXISTS;
finalizeCommand();
}
auditInfoList.add(new Pair<>(executor.getParsedStmt(), executor.getQueryStatisticsForAuditLog()));
alreadyAddedToAuditInfoList = true;
}
} catch (IOException e) {
// ... 省略 ....
}










网友评论