1、 问题
如何解析SQL,并且获取SQL中关键数据?
- 操作类型 (删除、插入、更新、添加字段)
- 库名
- 表名
2、 背景
数据治理项目中,监控业务库人工提单操作数据库的SQL,提前发现可能对数仓跑批或者数据质量造成危害的操作。
危害操作如下:
- 导致【数据同步丢失】的操作:
- 数据删除:数仓跑批不能发现,导数据一致性出现问题
- 数据更新:不能有指定 updatetime 字段,会导致数仓同步数据丢失,数据一致性出现问题
- 数据插入:同上,不能指定 updatetime
- 导致【表发现失败】的操作:
- 重命名表:导致数仓ETL操作无法查到表名报错
- 重命名字段:同上,无法查询到字段名
- 删字段:同上
- 导致【ods表结构同步不及时】的操作(非危险操作,正常业务发展都可能添加字段):
- 添加字段:业务库添加了字段,ods层需要及时发现重做
理论上业务库是不允许有删数据、删表、重命名等操作。
根据以上逻辑,需要从提单的SQL中发现
- 操作类型
- 库名
- 表名
当解析出的表是数仓ods层同步过的表,同时操作类型是我们关注的类型,发出告警通知!
3、 方案预选
粗糙的方案:解析关键字,获取操作类型
- 优点:简单,方便,甚至粗暴
- 缺点:无法获取表名,不能解决我们需要判断是否同步到了数仓的功能
词法分析SQL解析器
- 优点:能解析出各种操作类型、库名、表名等
- 缺点:自己开发,可能没有这个能力
综上:最终选取了github上的一个项目,能解析出我们需要的三个关键属性
https://github.com/melin/bigdata-sql-parser
4、 方案实施
打包且install 到mvn里之后,Java项目就能使用了
伪代码如下:
import com.github.bigdata.sql.parser.*;
import com.github.bigdata.sql.parser.tidb.TidbSQLHelper;
import java.util.ArrayList;
String sql = "select col from db_name.table_name ";
StatementData statementData = TidbSQLHelper.getStatementData(sql);
//打印statementData,详见下一个代码块
System.out.print(statementData.toString())
Statement statement = statementData.getStatement();
// 获取操作类型
StatementType statementType = statementData.getType();
ArrayList<com.github.bigdata.sql.parser.TableSource> inputTables = ((TableData) statement).getInputTables();
TableSource tableSource = inputTables.get(0);
//获取库名
String database = tableSource.getDatabaseName();
//获取表名
String tableName = tableSource.getTableName();
statementData 打印结果如下:
StatementData(type=SELECT, statement=TableData(inputTables=[TableSource(databaseName=db_name, tableName=table_name, column=null, columns=[])], outpuTables=[], limit=null))
需要注意的是,不同的数据库操作类型获取库名和表名的方法不一样
5、 应用拓展
- 判断业务库SQL变更是否对数仓表产生影响(本文)
- 对用户提交的SQL进行鉴权,判断是否有该表操作权限
- 数仓血缘关系
其他应用需求欢迎补充