美团开源 SQL 优化工具 SQLAdvisor

摘要:
开发团队表示,目前SQL Advisor在美团广泛使用,相对成熟稳定,开源版本和内部版本完全一致。它希望与行业中有类似需求的团队合作,创建一个优秀的SQL优化产品。SQLAdvisor原则描述了两种类型的连接处理语法:Joinin和Joinusing。Joinin有时以where条件存在。Groupby优于Orderby,同时只能存在一个。

https://www.oschina.net/news/82725/sqladvisor-opensource

https://github.com/Meituan-Dianping/SQLAdvisor

SQLAdvisor 是由美团点评公司北京 DBA 团队开发维护的 SQL 优化工具:输入SQL,输出索引优化建议,现已开源。 它基于 MySQL 原生词法解析,再结合 SQL 中的 where 条件以及字段选择度、聚合条件、多表 Join 关系等最终输出最优的索引优化建议。开发团队称目前 SQLAdvisor 在美团内部大量使用,较为成熟、稳定,且开源版本和内部使用版本保持完全一致,希望与业内有类似需求的团队,一起打造一款优秀的 SQL 优化产品。

SQLAdvisor 架构流程图:

美团开源 SQL 优化工具 SQLAdvisor第1张

SQLAdvisor 使用举例

sql: SELECT id FROM crm_loan WHERE id_card = '1234567'
cmd: ./sqladvisor -h xx -P xx -u xx -pxx -d xx -q "SELECT id FROM crm_loan WHERE id_card = '1234567'"
SQLAdvisor输出: alter table crm_loan add index idx_id_card(id_card)

SQLAdvisor 快速入门教程

SQLAdvisor 的优点

  • 基于 MySQL 原生词法解析,充分保证词法解析的性能、准确定以及稳定性;

  • 支持常见的 SQL(Insert/Delete/Update/Select);

  • 支持多表 Join 并自动逻辑选定驱动表;

  • 支持聚合条件 Order by 和 Group by;

  • 过滤表中已存在的索引。

SQLAdvisor 原理介绍

Join 处理

  1. Join语法分为两种:Join on 和 Join using,且 Join on 有时会存在 where 条件中。

  2. 分析 Join 条件首先会得到一个 nested_join 的 table list,通过判断它 join_using_fields 字段是否为空来区分 Join on 与 Join using。

  3. 生成的 table list 以二叉树的形式进行存储,以后序遍历的方式对二叉树进行遍历。

  4. 生成内部解析树时,right Join 会转换成 left Join。

  5. Join 条件会存在当层的叶子节点上,如果左右节点都是叶子节点,会存在右叶子节点。

  6. 每一个非叶子节点代表一次 Join 的结果。

上述实现时,涉及的函数为:mysql_sql_parse_join(TABLE_LIST join_table) mysql_sql_parse_join(Item join_condition) ,主要流程图如下:

美团开源 SQL 优化工具 SQLAdvisor第2张

where 处理

  1. 主要是提取 SQL 语句的 where 条件。where 条件中一般由 AND 和 OR 连接符进行连接,因为 OR 比较难以处理,所以忽略,只处理 AND 连接符。

  2. 由于 where 条件中可以存在 Join 条件,因此需要进行区分。

  3. 依次获取 where 条件,当条件中的操作符是 like,如果不是前缀匹配则丢弃这个条件。

  4. 根据条件计算字段的区分度按照高低进行倒序排,如果小于30则丢弃。同时使用最左原则将 where 条件进行有序排列。

计算区分度

  1. 通过 “show table status like” 获得表的总行数 table_count。

  2. 通过计算选择表中已存在的区分度最高的索引 best_index,同时Primary key > Unique key > 一般索引。

  3. 通过计算获取数据采样的起始值offset与采样范围rand_rows:

  • offset = (table_count / 2) > 10W ? 10W : (table_count / 2)

  • rand_rows =(table_count / 2) > 1W ? 1W : (table_count / 2)

  • 使用select count(1) from (select field from table force index(best_index) order by cl.. desc limit rand_rows) where field_print 得到满足条件的rows。

  • cardinality = rows == 0 ? rand_rows : rand_rows / rows;

  • 计算完成选择度后,会根据选择度大小,将该条件添加到该表中的备选索引中。

主要涉及的函数为:mysql_sql_parse_field_cardinality_new() 计算选择度。

美团开源 SQL 优化工具 SQLAdvisor第3张

添加备选索引

  1. mysql_sql_parse_index()将条件按选择度添加到备选索引链表中。

  2. 上述两函数的流程图如下所示:

美团开源 SQL 优化工具 SQLAdvisor第4张

Group 与 Order 处理

  1. Group 字段与 Order 字段能否用上索引,需要满足如下条件:

  • 涉及到的字段必须来自于同一张表,并且这张表必须是确定下来的驱动表。

  • Group by 优于 Order by, 两者只能同时存在一个。

  • Order by 字段的排序方向必须完全一致,否则丢弃整个 Order by 字段列。

  • 当 Order by 条件中包含主键时,如果主键字段为 Order by。 字段列末尾,忽略该主键,否则丢弃整个 Order by 字段列。

  • 整个索引列排序优先级:等值>(group by | order by )> 非等值。

  • 该过程中设计的函数主要有:

    • mysql_sql_parse_group() 判断 Group 后的字段是否均来自于同一张表。

    • mysql_sql_parse_order() 判断 Order 后的条件是否可以使用。

    • mysql_sql_parse_group_order_add() 将字段依次按照规则添加到备选索引链表中。

    美团开源 SQL 优化工具 SQLAdvisor第5张

    美团开源 SQL 优化工具 SQLAdvisor第6张

    驱动表选择

    1. 经过前期的 where 解析、Join 解析,已经将 SQL 中表关联关系存储起来,并且按照一定逻辑将候选驱动表确定下来。

    2. 在侯选驱动表中,按照每一张表的侯选索引字段中第一个字段进行计算表中结果集大小。

    3. 使用 explain select * from table where field 来计算表中结果集。

    4. 结果集小最小的被确为驱动表。

    5. 步骤中涉及的函数为:final_table_drived(),在该函数中,调用了函数 get_join_table_result_set() 来获取每张驱动候选表的行数。

    添加被驱动表备选索引

    1. 通过上述过程,已经选择驱动表,也通过解析保存了语句中的条件。

    2. 由于选定了驱动表,因此需要对被驱动表的索引,根据 Join 条件进行添加。

    3. 该过程涉及的函数主要是:mysql_index_add_condition_field(),流程如下:

    美团开源 SQL 优化工具 SQLAdvisor第7张

    输出建议

    1. 通过上述步骤,已经将每张表的备选索引键全部保存。此时,只要判断每张表中的候选索引键是否在实际表中已存在。没有索引,则给出建议增加对应的索引。

    2. 该步骤涉及的函数是:print_index() ,主要的流程图为:

    美团开源 SQL 优化工具 SQLAdvisor第8张

    免责声明:文章转载自《美团开源 SQL 优化工具 SQLAdvisor》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

    上篇后台生成textbox并设置多行属性,自动换行Hive速览下篇

    宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

    相关文章

    SQL优化

    SQL优化   sql执行性能低、执行时间长、等待时间长、SQL语句欠佳(连接查询)、索引失效、服务器参数设置。 (1.)SQL解析过程: 编写过程:select distinct ... from ... join..on..where..group by...having...order 解析过程:from .. on.. join..where.....

    antd-vue中table行高亮效果实现

    【方式一】:通过设置customRow达到目的,点击时遍历所有行设置为正常颜色,把当前行设置为特殊颜色(高亮色) HTML: <a-table ref="table"size="small"rowKey="id"bordered :columns="physicalSurveyColumns":data-source="physicalSur...

    Mysql字符集设置

    最近,在项目组使用的mysql数据库中,插入数据出现乱码,关于这个问题做了下总结,我们从最基本的地方说起,到错误产生的深层次原因和解决办法。 基本概念 • 字符(Character)是指人类语言中最小的表义符号。例如’A'、’B'等;• 给定一系列字符,对每个字符赋予一个数值,用数值来代表对应的字符,这一数值就是字符的编码(Encoding)。例如,我们给...

    linux下mysql的大小写是否区分设置

    转:http://blog.csdn.net/qq_29246225/article/details/52293549 一、Linux中MySQL大小写详情:1、数据库名严格区分大小写2、表名严格区分大小写的3、表的别名严格区分大小写4、变量名严格区分大小写5、列名在所有的情况下均忽略大小写6、列的别名在所有的情况下均忽略大小写 二、设置MySQL表名不区...

    MySQL连接池

    一. 什么是数据库连接池 官方:数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对连接池中的连接进行申请,使用,释放。 理解:创建数据库连接池是一个很耗时的操作,也容易对数据库造成安全隐患。所以,在程序初始化的时候,集中创建多个数据库连接池,并把他们集中管理,供程序使用,可以保证...

    mysql常用的聚合函数

    GROUP BY(聚合)函数本章论述了用于一组数值操作的 group (集合)函数。除非另作说明, group 函数会忽略 NULL 值。 假如你在一个不包含 ROUP BY子句的语句中使用一个 group函数 ,它相当于对所有行进行分组。 AVG([DISTINCT] expr) 返回expr 的平均值。 DISTINCT 选项可用于返回 expr的不同...