在信也,数据驱动业务决策的理念贯穿始终,大数据分析在挖掘潜在价值、助力业务增长方面起着关键作用。而 SQL 作为大数据分析的核心工具之一,能够从海量数据中精准检索有价值的信息,为业务的精细化运营和战略规划提供有力支持,是实现大数据价值转化的重要环节。
然而,在实际的业务场景中,SQL 的运算对集群资源有着较高的需求,而公司集群的资源总量存在上限。尤其是在业务繁忙的高峰时段,如每月的业务结算期、特定营销活动推广期间等,集群的空闲资源急剧减少。此时,未经优化的 SQL 语句会进一步加剧资源竞争,导致查询效率降低,甚至影响到关键业务系统的正常运行,给业务方带来不便,也可能造成潜在的业务损失。
为了有效应对这一挑战,在信也,我们成功实现了一套基于 SQL 执行前的表级血缘分析与质量评分机制。通过对 SQL 语句进行提前分析,精准识别其中涉及的表之间的血缘关系,并对 SQL 质量进行量化评分,从而实现了资源峰值削峰与慢 SQL 提前拦截的双重目标。
方案基于ANTLR4实现(ANother Tool for Language Recognition 4),它能依据特定的语法规则,把输入的文本转化为可处理的数据结构,让开发者可以轻松构建出编译器、解释器、语法检查器等。
简单来说就是一种语法分析生成器,可以自定义语法规则,来达到分块解析的目的。
工作原理
SQL文本中带有数据流向,例如insert into A表 select from B表
这段SQL文本的数据流向为由B表到A表,解析SQL文本需要做到3点。
create...select...
语法和insert...select...
语法会带有数据流向。INSERT INTO A SELECT FROM B
中的A→B
流向,支持子查询嵌套场景(识别率 99.97%)。//传参SQL内容
create table if not exists test.test_zyc03 as
select
t1.*
from
test.test_zyc01 t1
left join test.test_zyc02 t2 on t1.userid = t2.userid;
//接口返回值
{
"code": 200,
"msg": "成功",
"data": [
{
"sqlType": "create_as", //sql语法类型
"outputTable": [ //输出表
{
"dbName": "test",
"tableName": "test_zyc03"
}
],
"withTable": [],
"cacheTable": [],
"inputTables": [ //输入表
{
"dbName": "test",
"tableName": "test_zyc02"
},
{
"dbName": "test",
"tableName": "test_zyc01"
}
],
"allTables": [
{
"dbName": "test",
"tableName": "test_zyc03"
},
{
"dbName": "test",
"tableName": "test_zyc02"
},
{
"dbName": "test",
"tableName": "test_zyc01"
}
]
}
]
}
利用Antlr4工具对SQL解析除了可以精准获取信息外,还有一大特点就是速度快,SQL的平均解析速度在20ms左右,获取SQL中的字段名,表名,分区字段等信息,再结合表的元数据信息,就可以在SQL执行前对当前SQL质量做一个判断。
当用户执行一段SQL时,会先进行解析和打分操作并将结果返回给用户,返回内容包含扣分原因和修改建议,用户根据分值判断是否执行该段SQL。整个打分过程只需要消耗几十毫秒,可以在慢SQL运行前及时遏止,防止对于集群资源的大量消耗。首先把能够被收集到的信息罗列出来,查看哪些信息是可以被类用的。
规则 | 触发条件 | 优化建议 |
全表扫描(SELECT *) | 表字段 > 500 个 | 显式指定必要字段 |
分区表无分区过滤 | WHERE 无分区字段 | 显式添加分区键范围过滤 |
笛卡尔积 JOIN | ON 条件缺失 | 补充 JOIN 字段 |
动态分区错位 | SELECT 末列≠分区字段数 | 检查字段顺序与分区定义 |
在指定好上述打分规则后,即可对SQL进行解析和打分,大致逻辑如下:
只通过SQL文本和Hive元数据库中获取到的信息有限,还不足以涵盖所有的慢SQL查询场景。公司分析师使用的SQL引擎大多数是impala引擎,explain
中含有更为信息的数据指标,并且执行explain
会比正常执行快的多,如果能够将explain
中的信息解析提取并加以利用,就可以更好的辅助SQL前置打分系统。第二层解析耗时为几十毫秒,两层解析可并行进行,将扣分结果合并后返回用户。
难点在于没有任何explain解析器可以参考,需要从零基于Antlr4工具进行研发,这里只针对implain引擎的explain文本进行了涉及与实现。
impala explain文本示例:
MAX PER-HOST RESOURCE RESERVATION: MEMORY=72.00MB THREADS=4
PER-HOST RESOURCE ESTIMATES: MEMORY=316MB
WARNING: THE FOLLOWING TABLES ARE MISSING RELEVANT TABLE AND/OR COLUMN STATISTICS.
ODS.CPU
ANALYZED QUERY: SELECT DISTINCT (SN) FROM ODS.CPU
F02:PLAN FRAGMENT [UNPARTITIONED] HOSTS=1 INSTANCES=1
PER-HOST RESOURCES: MEM-ESTIMATE=10.06MB MEM-RESERVATION=0B THREAD-RESERVATION=1
PLAN-ROOT SINK
| OUTPUT EXPRS: (SN)
| MEM-ESTIMATE=0B MEM-RESERVATION=0B THREAD-RESERVATION=0
|
04:EXCHANGE [UNPARTITIONED]
MEM-ESTIMATE=10.06MB MEM-RESERVATION=0B THREAD-RESERVATION=0
TUPLE-IDS=1 ROW-SIZE=12B CARDINALITY=1.04G
IN PIPELINES: 03(GETNEXT)
F01:PLAN FRAGMENT [HASH((SN))] HOSTS=4 INSTANCES=4
PER-HOST RESOURCES: MEM-ESTIMATE=138.06MB MEM-RESERVATION=34.00MB THREAD-RESERVATION=1
DATASTREAM SINK [FRAGMENT=F02, EXCHANGE=04, UNPARTITIONED]
| MEM-ESTIMATE=0B MEM-RESERVATION=0B THREAD-RESERVATION=0
03:AGGREGATE [FINALIZE]
| GROUP BY: (SN)
| MEM-ESTIMATE=128.00MB MEM-RESERVATION=34.00MB SPILL-BUFFER=2.00MB THREAD-RESERVATION=0
| TUPLE-IDS=1 ROW-SIZE=12B CARDINALITY=1.04G
| IN PIPELINES: 03(GETNEXT), 00(OPEN)
|
02:EXCHANGE [HASH((SN))]
MEM-ESTIMATE=10.06MB MEM-RESERVATION=0B THREAD-RESERVATION=0
TUPLE-IDS=1 ROW-SIZE=12B CARDINALITY=1.04G
IN PIPELINES: 00(GETNEXT)
F00:PLAN FRAGMENT [RANDOM] HOSTS=4 INSTANCES=4
PER-HOST RESOURCES: MEM-ESTIMATE=168.00MB MEM-RESERVATION=38.00MB THREAD-RESERVATION=2
DATASTREAM SINK [FRAGMENT=F01, EXCHANGE=02, HASH((SN))]
| MEM-ESTIMATE=0B MEM-RESERVATION=0B THREAD-RESERVATION=0
01:AGGREGATE [STREAMING]
| GROUP BY: (SN)
| MEM-ESTIMATE=128.00MB MEM-RESERVATION=34.00MB SPILL-BUFFER=2.00MB THREAD-RESERVATION=0
| TUPLE-IDS=1 ROW-SIZE=12B CARDINALITY=1.04G
| IN PIPELINES: 00(GETNEXT)
|
00:SCAN HDFS [ODS.CPU, RANDOM]
HDFS PARTITIONS=17/303 FILES=367 SIZE=9.40GB
STORED STATISTICS:
TABLE: ROWS=UNAVAILABLE SIZE=UNAVAILABLE
PARTITIONS: 17/17 ROWS=1.04G
COLUMNS: UNAVAILABLE
EXTRAPOLATED-ROWS=DISABLED MAX-SCAN-RANGE-ROWS=2.98M
MEM-ESTIMATE=40.00MB MEM-RESERVATION=4.00MB THREAD-RESERVATION=1
TUPLE-IDS=0 ROW-SIZE=12B CARDINALITY=1.04G
IN PIPELINES: 00(GETNEXT)
解析重点
MEM-ESTIMATE=138MB
)、扫描文件数(FILES=367
)、分区覆盖比(PARTITIONS=17/303
)EXCHANGE [BROADCAST]
且数据量 > 1GB)AGGREGATE [STREAMING]
嵌套FINALIZE
)解析器设计思路:
规则 | 触发条件 | 优化建议 |
单表扫描过多的分区 | 分区数 > 1000个 | SQL优化,减少扫描分区数量 |
单表扫描过多的文件 | 文件数 > 10000个 | 避免每个分区生成过多的小文件,合并小文件 |
广播过大的文件 | 广播表的大小超过阈值>1G | 减少广播表的数据量,调整 Join 策略 |
SQL节点预估使用内存大小 | 使用内存大小>5G | 优化聚合操作,拆分复杂查询 |
Java、大数据、前端、测试等各种技术岗位热招中,欢迎了解~
更多福利请关注官方订阅号信也科技拍黑米、拍码场