[ 更换 ]
热门城市
北京上海广州深圳成都杭州南京武汉天津西安重庆青岛沈阳长沙大连厦门无锡福州济南宁波昆明苏州郑州长春合肥南昌哈尔滨常州烟台南宁温州石家庄太原珠海南通扬州贵阳东莞徐州大庆佛山威海洛阳淮安呼和浩特镇江潍坊桂林中山临沂咸阳包头嘉兴惠州泉州三亚赣州九江金华泰安榆林许昌新乡舟山慈溪南阳聊城海口东营淄博漳州保定沧州丹东宜兴绍兴唐山湖州揭阳江阴营口衡阳郴州鄂尔多斯泰州义乌汕头宜昌大同鞍山湘潭盐城马鞍山襄樊长治日照常熟安庆吉林乌鲁木齐兰州秦皇岛肇庆西宁介休滨州台州廊坊邢台株洲德阳绵阳双流平顶山龙岩银川芜湖晋江连云港张家港锦州岳阳长沙县济宁邯郸江门齐齐哈尔昆山柳州绍兴县运城齐河衢州太仓张家口湛江眉山常德盘锦枣庄资阳宜宾赤峰余姚清远蚌埠宁德德州宝鸡牡丹江阜阳莆田诸暨黄石吉安延安拉萨海宁通辽黄山长乐安阳增城桐乡上虞辽阳遵义韶关泸州南平滁州温岭南充景德镇抚顺乌海荆门阳江曲靖邵阳宿迁荆州焦作丹阳丽水延吉茂名梅州渭南葫芦岛娄底滕州上饶富阳内江三明淮南孝感溧阳乐山临汾攀枝花阳泉长葛汉中四平六盘水安顺新余晋城自贡三门峡本溪防城港铁岭随州广安广元天水遂宁萍乡西双版纳绥化鹤壁湘西松原阜新酒泉张家界黔西南保山昭通河池来宾玉溪梧州鹰潭钦州云浮佳木斯克拉玛依呼伦贝尔贺州通化朝阳百色毕节贵港丽江安康德宏朔州伊犁文山楚雄嘉峪关凉山雅安西藏四川广东河北山西辽宁黑龙江江苏浙江安徽福建江西山东河南湖北湖南海南贵州云南陕西甘肃青海台湾内蒙古广西宁夏香港澳门
培训资讯网 - 为兴趣爱好者提供专业的职业培训资讯知识

拯救DBA!美团SQL解析探索实践

实践 探索

数据库作为核心的基础组件,是需要重点保护的对象。任何一个线上的不慎操作,都有可能给数据库带来严重的故障,从而给业务造成巨大的损失。

拯救DBA!美团SQL解析探索实践

为了避免这种损失,一般会在管理上下功夫。比如为研发人员制定数据库开发规范;新上线的 SQL,需要 DBA 进行审核;维护操作需要经过领导审批等等。

而且如果希望能够有效地管理这些措施,需要有效的数据库培训,还需要 DBA 细心的进行 SQL 审核。

很多中小型创业公司,可以通过设定规范、进行培训、完善审核流程来管理数据库。

随着美团业务的不断发展和壮大,上述措施的实施成本越来越高。如何更多的依赖技术手段,来提高效率,越来越受到重视。

业界已有不少基于 MySQL 源码开发的 SQL 审核、优化建议等工具,极大的减轻了 DBA 的 SQL 审核负担。

那么我们能否继续扩展 MySQL 的源码,来辅助 DBA 和研发人员来进一步提高效率呢?

比如,更全面的 SQL 优化功能;多维度的慢查询分析;辅助故障分析等。要实现上述功能,其中最核心的技术之一就是 SQL 解析。

现状与场景

SQL 解析是一项复杂的技术,一般都是由数据库厂商来掌握,当然也有公司专门提供 SQL 解析的 API。

由于这几年 MySQL 数据库中间件的兴起,需要支持读写分离、分库分表等功能,就必须从 SQL 中抽出表名、库名以及相关字段的值。

因此像 Java 语言编写的 Druid,C 语言编写的 MaxScale,Go 语言编写的 Kingshard 等,都会对 SQL 进行部分解析。

而真正把 SQL 解析技术用于数据库维护的产品较少,主要有如下几个:

美团点评开源的 SQLAdvisor。它基于 MySQL 原生态词法解析,结合分析 SQL 中的 where 条件、聚合条件、多表 Join 关系给出索引优化建议。

去哪儿开源的 Inception。侧重于根据内置的规则,对 SQL 进行审核。

阿里的 Cloud DBA。根据官方文档介绍,其也是提供 SQL 优化建议和改写。

上述产品都有非常合适的应用场景,在业界也被广泛使用。但是 SQL 解析的应用场景远远没有被充分发掘,比如:

基于表粒度的慢查询报表。比如,一个 Schema 中包含了属于不同业务线的数据表,那么从业务线的角度来说,其希望提供表粒度的慢查询报表。

生成 SQL 特征。将 SQL 语句中的值替换成问号,方便 SQL 归类。虽然可以使用正则表达式实现相同的功能,但是其 Bug 较多,可以参考 pt-query-digest。

比如 pt-query-digest 中,会把遇到的数字都替换成“?”,导致无法区别不同数字后缀的表。

高危操作确认与规避。比如,DBA 不小心 Drop 数据表,而此类操作,目前还无有效的工具进行回滚,尤其是大表,其后果将是灾难性的。

SQL 合法性判断。为了安全、审计、控制等方面的原因,美团点评不会让研发人员直接操作数据库,而是提供 RDS 服务。

尤其是对于数据变更,需要研发人员的上级主管进行业务上的审批。如果研发人员,写了一条语法错误的 SQL,而 RDS 无法判断该 SQL 是否合法,就会造成不必要的沟通成本。

因此为了让所有有需要的业务都能方便的使用 SQL 解析功能,我们认为应该具有如下特性:

直接暴露 SQL 解析接口,使用尽量简单。比如,输入 SQL,则输出表名、特征和优化建议。

接口的使用不依赖于特定的语言,否则维护和使用的代价太高。比如,以 HTTP 等方式提供服务。

千里之行,始于足下,下面我先介绍下 SQL 的解析原理。

SQL 解析原理

SQL 解析与优化属于编译器范畴,和 C 等其他语言的解析没有本质的区别。

其中分为,词法分析、语法和语义分析、优化、执行代码生成。对应到 MySQL 的部分,如下图:

拯救DBA!美团SQL解析探索实践

图 1:SQL 解析原理

词法分析

SQL 解析由词法分析和语法/语义分析两个部分组成。词法分析主要是把输入转化成一个个 Token。其中 Token 中包含 Keyword(也称 Symbol)和非 Keyword。

例如,SQL 语句 select username from userinfo,在分析之后,会得到 4 个 Token。

其中有 2 个 Keyword,分别为 select 和 from:

通常情况下,词法分析可以使用 Flex 来生成,但是 MySQL 并未使用该工具,而是手写了词法分析部分(据说是为了效率和灵活性,参考此文)。具体代码在 sql/lex.h 和 sql/sql_lex.cc 文件中。

MySQL 中的 Keyword 定义在 sql/lex.h 中,如下为部分 Keyword:

{ "&&", SYM(AND_AND_SYM)},

{ "<", SYM(LT)},

{ "<=", SYM(LE)},

{ "<>", SYM(NE)},

{ "!=", SYM(NE)},

{ "=", SYM(EQ)},

{ ">", SYM(GT_SYM)},

{ ">=", SYM(GE)},

{ "<<", SYM(SHIFT_LEFT)},

{ ">>", SYM(SHIFT_RIGHT)},

{ "<=>", SYM(EQUAL_SYM)},

{ "ACCESSIBLE", SYM(ACCESSIBLE_SYM)},

{ "ACTION", SYM(ACTION)},

{ "ADD", SYM(ADD)},

{ "AFTER", SYM(AFTER_SYM)},

{ "AGAINST", SYM(AGAINST)},

{ "AGGREGATE", SYM(AGGREGATE_SYM)},

{ "ALL", SYM(ALL)},

词法分析的核心代码在 sql/sql_lex.c 文件中的 MySQLLex→lex_one_Token,有兴趣的同学可以下载源码研究。

语法分析

语法分析就是生成语法树的过程。这是整个解析过程中最精华,最复杂的部分,不过这部分 MySQL 使用了 Bison 来完成。

即使如此,如何设计合适的数据结构以及相关算法,去存储和遍历所有的信息,也是值得在这里研究的。

语法分析树

SQL 语句:

select username, ismale from userinfo where age > 20 and level > 5 and 1 = 1

会生成如下语法树:

拯救DBA!美团SQL解析探索实践

图 2:语法树

对于未接触过编译器实现的同学,肯定会好奇如何才能生成这样的语法树。其背后的原理都是编译器的范畴。

本人也是在学习 MySQL 源码过程中,阅读了部分内容。由于编译器涉及的内容过多,本人经历和时间有限,不做过多探究。

从工程的角度来说,学会如何使用 Bison 去构建语法树,来解决实际问题,对我们的工作也许有更大帮助。下面我就以 Bison 为基础,探讨该过程。

MySQL 语法分析树生成过程

全部的源码在 sql/sql_yacc.yy 中,在 MySQL 5.6 中有 17K 行左右代码。这里列出涉及到的 SQL:

select username, ismale from userinfo where age > 20 and level > 5 and 1 = 1

解析过程的部分代码摘录出来。有了 Bison 之后,SQL 解析的难度也没有想象的那么大,特别是这里给出了解析的脉络之后。

select /*select语句入口*/:

select_init

{

LEX *lex= Lex;

lex->sql_command= SQLCOM_SELECT;

}

;

select_init:

SELECT_SYM /*select 关键字*/ select_init2

| "(" select_paren ")" union_opt

;

select_init2:

select_part2

{

LEX *lex= Lex;

SELECT_LEX * sel= lex->current_select;

if (lex->current_select->set_braces(0))

{

my_parse_error(ER(ER_SYNTAX_ERROR));

MYSQL_YYABORT;

}

if (sel->linkage == UNION_TYPE &&

sel->master_unit()->first_select()->braces)

{

my_parse_error(ER(ER_SYNTAX_ERROR));

MYSQL_YYABORT;

}

}

union_clause

;

select_part2:

{

LEX *lex= Lex;

SELECT_LEX *sel= lex->current_select;

if (sel->linkage != UNION_TYPE)

mysql_init_select(lex);

lex->current_select->parsing_place= SELECT_LIST;

}

select_options select_item_list /*解析列名*/

{

Select->parsing_place= NO_MATTER;

}

select_into select_lock_type

;

select_into:

opt_order_clause opt_limit_clause {}

| into

| select_from /*from 字句*/

| into select_from

| select_from into

;

select_from:

FROM join_table_list /*解析表名*/ where_clause /*where字句*/ group_clause having_clause

opt_order_clause opt_limit_clause procedure_analyse_clause

{

Select->context.table_list=

Select->context.first_name_resolution_table=

Select->table_list.first;

}

| FROM DUAL_SYM where_clause opt_limit_clause

/* oracle compatibility: oracle always requires FROM clause,

and DUAL is system table without fields.

Is "SELECT 1 FROM DUAL" any better than "SELECT 1" ?

Hmmm :) */

;

where_clause:

/* empty */ { Select->where= 0; }

| WHERE

{

Select->parsing_place= IN_WHERE;

}

expr /*各种表达式*/

{

SELECT_LEX *select= Select;

select->where= $3;

select->parsing_place= NO_MATTER;

if ($3)

$3->top_level_item();

}

;

/* all possible expressions */

expr:

| expr and expr %prec AND_SYM

{

/* See comments in rule expr: expr or expr */

Item_cond_and *item1;

Item_cond_and *item3;

if (is_cond_and($1))

{

item1= (Item_cond_and*) $1;

if (is_cond_and($3))

{

item3= (Item_cond_and*) $3;

/*

(X1 AND X2) AND (Y1 AND Y2) ==> AND (X1, X2, Y1, Y2)

*/

item3->add_at_head(item1->argument_list());

$$ = $3;

}

else

{

/*

(X1 AND X2) AND Y ==> AND (X1, X2, Y)

*/

item1->add($3);

$$ = $1;

}

}

else if (is_cond_and($3))

{

item3= (Item_cond_and*) $3;

/*

X AND (Y1 AND Y2) ==> AND (X, Y1, Y2)

*/

item3->add_at_head($1);

$$ = $3;

}

else

{

/* X AND Y */

$$ = new (YYTHD->mem_root) Item_cond_and($1, $3);

if ($$ == NULL)

MYSQL_YYABORT;

}

}

在大家浏览上述代码的过程,会发现 Bison 中嵌入了 C++ 的代码。通过 C++ 代码,把解析到的信息存储到相关对象中。

例如表信息会存储到 TABLE_LIST 中,order_list 存储 order by 子句里的信息,where 字句存储在 Item 中。

有了这些信息,再辅助以相应的算法就可以对 SQL 进行更进一步的处理了。

核心数据结构及其关系

在 SQL 解析中,最核心的结构是 SELECT_LEX,其定义在 sql/sql_lex.h 中。下面仅列出与上述例子相关的部分。

图 3:SQL 解析树结构

上面图示中,列名 username、ismale 存储在 item_list 中,表名存储在 table_list 中,条件存储在 where 中。

其中以 where 条件中的 Item 层次结构最深,表达也较为复杂,如下图所示:

拯救DBA!美团SQL解析探索实践

图 4:where 条件

SQL 解析应用

为了更深入的了解 SQL 解析器,这里给出 2 个应用 SQL 解析的例子。

无用条件去除

无用条件去除属于优化器的逻辑优化范畴,可以仅仅根据 SQL 本身以及表结构即可完成,其优化的情况也是较多的,代码在 sql/sql_optimizer.cc 文件中的 remove_eq_conds 函数。

为了避免过于繁琐的描述,以及大段代码的粘贴,这里通过图来分析以下四种情况:

1=1 and (m > 3 and n > 4)

1=2 and (m > 3 and n > 4)

1=1 or (m > 3 and n > 4)

1=2 or (m > 3 and n > 4)

拯救DBA!美团SQL解析探索实践

图 5:无用条件去除 a

拯救DBA!美团SQL解析探索实践

图 6:无用条件去除 b

拯救DBA!美团SQL解析探索实践

图 7:无用条件去除 c

拯救DBA!美团SQL解析探索实践

图 8:无用条件去除 d

如果对其代码实现有兴趣的同学,需要对 MySQL 中的一个重要数据结构 Item 类有所了解。

因为其比较复杂,所以 MySQL 官方文档,专门介绍了 Item 类。阿里的 MySQL 小组,也有类似的文章。如需更详细的了解,就需要去查看源码中 sql/item_* 等文件。

SQL 特征生成

为了确保数据库,这一系统基础组件稳定、高效运行,业界有很多辅助系统。比如慢查询系统、中间件系统。

这些系统采集、收到 SQL 之后,需要对 SQL 进行归类,以便统计信息或者应用相关策略。归类时,通常需要获取 SQL 特征。比如 SQL:

select username, ismale from userinfo where age > 20 and level > 5;

SQL 特征为:

select username, ismale from userinfo where age > ? and level > ?

业界著名的慢查询分析工具 pt-query-digest,通过正则表达式实现这个功能但是这类处理办法 Bug 较多。接下来就介绍如何使用 SQL 解析,完成 SQL 特征的生成。

SQL特征生成分两部分组成:

生成 Token 数组

根据 Token 数组,生成 SQL 特征

首先回顾在词法解析章节,我们介绍了 SQL 中的关键字,并且每个关键字都有一个 16 位的整数对应,而非关键字统一用 ident 表示,其也对应了一个 16 位整数。如下表:

将一个 SQL 转换成特征的过程:

在 SQL 解析过程中,可以很方便的完成 Token 数组的生成。而一旦完成 Token 数组的生成,就可以很简单的完成 SQL 特征的生成。

SQL 特征被广泛用于各个系统中,比如 pt-query-digest 需要根据特征对 SQL 归类,然而其基于正则表达式的实现有诸多 Bug。

下面列举几个已知 Bug:

拯救DBA!美团SQL解析探索实践

学习建议

最近,在对 SQL 解析器和优化器探索的过程中,从一开始的茫然无措到有章可循,也总结了一些心得体会,在这里跟大家分享一下:

阅读相关书籍,书籍能给我们一个系统的认识解析器和优化器的角度。但是该类针对 MySQL 的书籍市面上很少,目前中文作品可以看下《数据库查询优化器的艺术:原理解析与SQL性能优化》。

阅读

相关内容

怎么学?如何干?西藏7市(地)委书记在西藏日报发表文章

启航新征程 开创新局面为全面建设社会主义现代化新拉萨努力奋斗自治区党委常委、拉萨市委书记 普布顿珠党的二十大大笔擘画坚持以中国式现代化全面推进中华民族伟大复兴的宏伟蓝图,区党委十届三次全会全面铺开建设美丽幸福西藏、共圆伟大复兴梦想的壮阔实践···

2023年全区智慧旅游专业人才培训班圆满结业

6月2日,自治区旅游发展厅主办的全区智慧旅游专业人才培训班在拉萨圆满结业。培训共历时三天,累计完成全区旅游行政管理部门工作人员及涉旅企业专业技术人员培训100人。本次培训是区旅发厅深入推进学习贯彻习近平新时代中国特色社会主义思想主题教育重要···

徐汇萨迦共同举办大美西藏首届口腔学习班

随着现代医学的发展,口腔健康越来越受到人们的关注,为提高西藏地区口腔技术水平和服务质量,近日,徐汇区牙病防治所和萨迦县中心医院远程连线共同举办首届口腔学习班开班仪式。徐汇区卫生健康委副主任胡强,上海援藏干部、萨迦县委常务副书记、常务副县长沈···

自觉抵制“一对一”“一对多”等学科类培训!哈尔滨中小学生暑期预警来了

17日,记者从哈尔滨市各区教育局获悉,2023年暑假将至,南岗区、道里区、香坊区教育局向家长发出预警,自觉抵制违规培训,各区义务教育阶段学科类培训机构已经全部注销,暑假期间以任何形式开展的学科类培训均属于违规培训。家长要自觉抵制任何机构或个···

哈尔滨市道里区企投局举办“招商大讲堂”专题培训

黑龙江网讯(记者 王惠婷)10月24日,哈尔滨市道里区企投局组织开展“招商大讲堂”专题培训班,全区各招商专班负责同志及业务骨干参加培训。本次培训从实际需求出发,紧紧围绕当前招商工作中的热点、难点,对“什么是招商引资”“道里区的产业结构和主导···

团黑龙江省委举办全省青年文明号青年岗位能手学习宣传贯彻党的二十大精神培训交流会

中国青年报客户端讯(李海涛)为深入学习贯彻党的二十大精神,充分发挥青年文明号、青年岗位能手示范引领作用,在全省职业青年中掀起学习党的二十大精神热潮,11月22日,团黑龙江省委举办全省青年文明号青年岗位能手学习宣传贯彻党的二十大精神培训交流会···

辽宁葫芦岛举办外贸政策培训会推动外贸保稳增量

辽宁省葫芦岛市外贸政策培训会4月3日举办。 辽宁省贸促会供图中新网葫芦岛4月3日电 (李晛)辽宁省葫芦岛市外贸政策培训会4月3日举办。本次活动由辽宁省贸促会支持、葫芦岛市商务局主办,葫芦岛市贸促会、葫芦岛海关、中国出口信用保险辽宁分公司和辽···

山西运城:严查无证校外培训机构 查封9家警告2家

新华社太原8月5日电(记者王飞航)记者从山西省运城市政府了解到,运城市教育局近日联合市公安局等多家单位,对中心城区无证校外培训机构进行了一次突击检查,共检查了13家校外培训机构,查封9家,警告2家,发放整改通知书4份。今年7月,运城市教育局···

山西开展培训筑牢森林“防火墙”

山西新闻网3月30日讯(记者 卢奕如)今日,记者从山西省应急管理厅获悉,全省举办森林草原防灭火业务培训,邀请专家以视频会议形式,围绕森林扑火指挥实操、森林草原火灾防控经验做法、火灾现场各级各类指挥员具体操作中遇到的问题等内容进行授课。培训内···

校外培训机构治理工作取得进展 山西停办近1300所

资料图:小学生排队等待进入校园。中新社记者 刘文华 摄中新网5月11日电 据教育部网站消息,按照校外培训机构专项治理工作整体安排,教育部、民政部、国家市场监管总局启动了校外培训机构治理专项督查工作。5月9日至10日,督查组率先在北京市开展华···

山西综改区举办省技术创新中心申报培训

  8月18日,山西综改区科技金融部举办2023年度省技术创新中心申报培训会,来自区内企业、科研院所及有关单位代表160余人参加了培训。  山西省技术创新中心是以产业前沿引领技术和关键共性技术研发为核心的产业技术创新平台,承担着为区域和产业···

山西汾阳医院开展健康教育与控烟知识培训

来源:【吕梁日报-吕梁新闻网】本报讯 (记者 刘少伟) 5月18日,在“世界无烟日”到来之际,山西汾阳医院组织开展健康教育与控烟知识培训。近年来,山西汾阳医院全面落实健康中国战略,根据国家卫健委《关于2011年起全国医疗卫生系统全面禁烟的决···

山西省文物局年度田野考古技术培训班开班

10月10日,山西省文物局在运城闻喜上郭城址、邱家庄墓群举办2023年度田野考古技术培训班开班仪式。该次培训为期三个月,通过理论和实践两部分教学,旨在推进山西考古工作高质量发展,提升考古业务人员专业技术水平。本次培训由山西省考古研究院和山西···

最低每课时9元!全省学科类校外培训课时长和收费标准出台

近日,山西省发改委、省教育厅下发《关于中小学学科类校外培训收费标准及有关事项的通知》,明确全省中小学学科类校外培训收费标准,从12月17日起执行。《通知》对全省线上线下学科类校外培训基准收费标准和浮动幅度制定了科学标准。其中,义务教育阶段线···

山西天镇 阳光职业培训学校培养乡村“新农人”乡村振兴添动能

(记者 贺文生) 山西天镇县阳光职业培训学校紧紧围绕乡村振兴战略,按照“政府引导、农民自愿、立足产业、突出重点”的原则,创新高素质农民技能培训方式方法,采取以“授人以渔”的方式,让人才振兴成为助推农业农村现代化的内生动力,以高素质农民引领现···

山西:建立全过程 全链条 无缝隙安全培训制度

黄河新闻网讯(记者杨江涛)日前,山西省应急管理厅下发了《山西省安全培训管理暂行办法》(以下简称《办法》)。我省将进一步抓好安全生产这个基本盘、基本面,推动全省安全培训工作制度化、规范化、科学化,促进安全培训工作高质量发展。山西省应急管理厅厅···

山西:艺考培训机构纳入全国监管平台管理

央广网太原10月6日消息(记者郎麒) 日前,山西省教育厅、省发改委、省公安厅等部门联合制定《加强面向高中阶段学生艺考培训规范管理工作方案》,针对艺考培训的突出特点和实际情况,全面规范艺考培训行为,将艺考培训机构统一纳入全国校外教育培训监管与···

太平财险阳泉中支开展消防安全教育和有限空间作业培训

为强化员工安全意识,进一步提升员工消防和有限空间突发事件应急处理能力,9月14日,太平财险阳泉中支邀请北京市卫民安消防教育咨询中心山西分中心讲师向全体员工开展了一次消防安全教育和有限空间作业课程培训。按照防消结合、预防为主的原则,本次讲座通···

山西省数字化转型贯标试点工作宣贯培训会在太原举行

  10月20日消息,山西省数字化转型贯标试点工作宣贯培训会在太原举行。省工信厅介绍,作为国家数字化转型贯标试点省份,试点启动后将引导企业加快数字化转型,助力制造业高端化、智能化、绿色化发展。  今年,工信部启动数字化转型贯标试点工作,我省···

山西马兰花创业培训讲师大赛收官 太原市获多个奖项

山西新闻网8月31日讯(记者 冯耿姝)8月29日,山西省第四届马兰花创业培训讲师大赛圆满收官,太原市代表队在比赛中分获多个二、三等奖和优秀奖。本届大赛以“启迪创新思维·激发创业梦想”为主题,全省共有56名教师晋级复赛,其中,太原市有7名选手···