正文
Inside君发现很少有人能够完成讲明白MySQL的Join类型与算法,网上流传着的要提升Join性能,加大变量join_buffer_size的谬论更是随处可见。当然,也有一些无知的PGer攻击MySQL不支持Hash Join,所以不适合一些分析类的操作。MySQL的确不支持Hash Join,也不支持Sort Merge Join,但是MySQL在Join上也有自己的独特的优化与处理,此外,分支版本MariaDB已支持Hash Join,因此拿MySQL来做一些“简单”的分析查询也是完全能够接受的。当然,如果数据量真的上去了,那么即使支持Hash Join的传统MPP架构的关系型数据库可能也是不合适的,这类分析查询或许应该交给更为专业的Hadoop集群来计算。
 
Join的成本
在讲述MySQL的Join类型与算法前,看看两张表的Join的过程:

上图的Fetch阶段是指当内表关联的列是辅助索引时,但是需要访问表中的数据,那么这时就需要再访问主键索引才能得到数据的过程,不论表的存储引擎是InnoDB存储引擎还是MyISAM,这都是无法避免的,只是MyISAM的回表速度要快点,因为其辅助索引存放的就是指向记录的指针,而InnoDB存储引擎是索引组织表,需要再次通过索引查找才能定位数据。
 
Fetch阶段也不是必须存在的,如果是聚集索引链接,那么直接就能得到数据,无需回表,也就没有Fetch这个阶段。另外,上述给出了两张表之间的Join过程,多张表的Join就是继续上述这个过程。
 
接着计算两张表Join的成本,这里有下列几种概念:
外表的扫描次数,记为O。通常外表的扫描次数都是1,即Join时扫描一次驱动表的数据即可
内表的扫描次数,记为I。根据不同Join算法,内表的扫描次数不同
读取表的记录数,记为R。根据不同Join算法,读取记录的数量可能不同
Join的比较次数,记为M。根据不同Join算法,比较次数不同
回表的读取记录的数,记为F。若Join的是辅助索引,可能需要回表取得最终的数据
 
评判一个Join算法是否优劣,就是查看上述这些操作的开销是否比较小。当然,这还要考虑I/O的访问方式,顺序还是随机,总之Join的调优也是门艺术,并非想象的那么简单。
 
Simple Nested-Loop Join
 
网上大部分说MySQL只支持Nested-Loop Join,故性能差。但是Nested-Loop join一定差吗?Hash Join比Nested-Loop Join强?Inside君感觉这样的理解都是片面的,Hash Join可能仅是Nested-Loop Join的一种变种。所以Inside君打算从算法的角度来分析MySQL支持的Join,并以此分析对于Join语句的优化。
 
首先来看Simple Nested-Loop Join(以下简称SNLJ),也就是最朴素的Nested-Loop Join,其算法伪代码如下所示:
 
For each row r in R do 
  Foreach row s in S do 
    If r and s satisfy the join condition 
      Then output the tuple
 
下图能更好地显示整个SNLJ的过程:

SNLJ的算法相当简单、直接。即外表(驱动表)中的每一条记录与内表中的记录进行判断。但是这个算法也是相当粗暴的,粗暴的原因在于这个算法的开销其实非常大。假设外表的记录数为R,内表的记录数位S,根据上一节Inside君对于Join算法的评判标准来看,SNLJ的开销如下表所示:

可以看到读取记录数的成本和比较次数的成本都是S*R,也就是笛卡儿积。假设外表内表都是1万条记录,那么其读取的记录数量和Join的比较次数都需要上亿。这样的算法开销,Inside君也只能:呵呵。
 
Index Nested-Loop Join
 
SNLJ算法虽然简单明了,但是也是相当的粗暴。因此,在Join的优化时候,通常都会建议在内表建立索引,以此降低Nested-Loop Join算法的开销,MySQL数据库中使用较多的就是这种算法,以下称为INLJ。来看这种算法的伪代码:
 
For each row r in R do 
 lookupr in S index 
   if found s == r
      Then output the tuple
 
由于内表上有索引,所以比较的时候不再需要一条条记录进行比较,而可以通过索引来减少比较,从而加速查询。整个过程如下图所示:

可以看到外表中的每条记录通过内表的索引进行访问,因为索引查询的成本是比较固定的,故优化器都倾向于使用记录数少的表作为外表(这里是否又会存在潜在的问题呢?)。故INLJ的算法成本如下表所示:

上表Smatch表示通过索引找到匹配的记录数量。同时可以发现,通过索引可以大幅降低内表的Join的比较次数,每次比较1条外表的记录,其实就是一次indexlookup(索引查找),而每次index lookup的成本就是树的高度,即IndexHeight。
 
INLJ的算法并不复杂,也算简单易懂。但是效率是否能达到用户的预期呢?其实如果是通过表的主键索引进行Join,即使是大数据量的情况下,INLJ的效率亦是相当不错的。因为索引查找的开销非常小,并且访问模式也是顺序的(假设大多数聚集索引的访问都是比较顺序的)。
 
大部分人诟病MySQL的INLJ慢,主要是因为在进行Join的时候可能用到的索引并不是主键的聚集索引,而是辅助索引,这时INLJ的过程又需要多一步Fetch的过程,而且这个过程开销会相当的大:

由于访问的是辅助索引,如果查询需要访问聚集索引上的列,那么必要需要进行回表取数据,看似每条记录只是多了一次回表操作,但这才是
由于访问的是辅助索引,如果查询需要访问聚集索引上的列,那么必要需要进行回表取数据,看似每条记录只是多了一次回表操作,但这才是INLJ算法最大的弊端。首先,辅助索引的index lookup是比较随机I/O访问操作。其次,根据index lookup再进行回表又是一个随机的I/O操作。所以说,INLJ最大的弊端是其可能需要大量的离散操作,这在SSD出现之前是最大的瓶颈。而即使SSD的出现大幅提升了随机的访问性能,但是对比顺序I/O,其还是慢了很多,依然不在一个数量级上。
 

MySQL Join算法与调优白皮书(一)的更多相关文章

  1. MySQL Join算法与调优白皮书(二)

    Index Nested-Loop Join   (接上篇)由于访问的是辅助索引,如果查询需要访问聚集索引上的列,那么必要需要进行回表取数据,看似每条记录只是多了一次回表操作,但这才是INLJ算法最大 ...

  2. MySQL Join算法与调优白皮书(三)

    Batched Key Access Join Index Nested-Loop Join虽好,但是通过辅助索引进行链接后需要回表,这里需要大量的随机I/O操作.若能优化随机I/O,那么就能极大的提 ...

  3. 【叶问】 MySQL常用的sql调优手段或工具有哪些

     MySQL常用的sql调优手段或工具有哪些1.根据执行计划优化   通常使用desc或explain,另外可以添加format=json来输出更详细的json格式的执行计划,主要注意点如下:     ...

  4. mysql监控、性能调优及三范式理解

    原文:mysql监控.性能调优及三范式理解 1监控 工具:sp on mysql     sp系列可监控各种数据库 2调优 2.1 DB层操作与调优 2.1.1.开启慢查询 在My.cnf文件中添加如 ...

  5. MySQL性能诊断与调优 转

    http://www.cnblogs.com/preftest/ http://www.highperfmysql.com/     BOOK LAMP 系统性能调优,第 3 部分: MySQL 服务 ...

  6. MySQL插入数据性能调优

    插入数据性能调优总结: 1.SQL插入语句调优 2.如果是InnoDB引擎的话,尝试开启事务,批量提交 3.调整MySQl数据库配置     参考: 百度空间 - MySQL插入数据性能调优 CSDN ...

  7. MySQL性能诊断与调优

    LAMP 系统性能调优,第 3 部分: MySQL 服务器调优http://www.ibm.com/developerworks/cn/linux/l-tune-lamp-3.html LoadRun ...

  8. MySQL索引和SQL调优手册

    MySQL索引 MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等.为了避免混乱,本文将只关注于BTree ...

  9. mysql 索引优化 性能调优 锁

    1 检查mysql 是否安装 rpm -qa|grep -i mysql 2 ntsysv 查看和设置开机启动列表 3 mysql 在 centos 上默认 的数据目录是 /var/lib/mysql ...

随机推荐

  1. Access control allow origin 简单请求和复杂请求

    原文地址:http://blog.csdn.net/wangjun5159/article/details/49096445 错误信息: XMLHttpRequest cannot load http ...

  2. SVM之解决线性不可分

    SVM之问题形式化 SVM之对偶问题 SVM之核函数 >>>SVM之解决线性不可分 写在SVM之前——凸优化与对偶问题 上一篇SVM之核函数介绍了通过计算样本核函数,实际上将样本映射 ...

  3. log4cpp单例类封装

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  4. 【Html 学习笔记】第八节——表单实践

    列举一些实践的例子: 1.点击按钮后跳转: <html> <body> <form action="1.html"> First <inp ...

  5. Week14《Java程序设计》第14次作业总结

    Week14<Java程序设计>第14次作业总结 1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结与数据库相关内容. 2. 使用数据库技术改造你的系统 2.1 简述如何 ...

  6. 初次使用Quartus II 13.0的疑惑及解决方法

    初次接触Quartus II 13.0,遇到了很多的问题,把问题总结如下: 1.Quartus II 13.0的安装及破解 下载地址:http://t.cn/Rh2TFcz,密码是:g3gc (参考贴 ...

  7. 浅析Postgres中的并发控制(Concurrency Control)与事务特性(上)(转)

    这篇博客将MVCC讲的很透彻,以前自己懂了,很难给别人讲出来,但是这篇文章给的例子就让人很容易的复述出来,因此想记录一下,转载给更多的人 转自:https://www.cnblogs.com/flyi ...

  8. Ubuntu 中sendmail 的安装、配置与发送邮件的具体实现

    一.安装 ubuntu中sendmail函数可以很方便的发送邮件,ubuntu sendmail先要安装两个包. 必需安装的两个包: 代码  sudo apt-get install sendmail ...

  9. (转)MapReduce Design Patterns(chapter 2 (part 2))(三)

    Median and standard deviation 中值和标准差的计算比前面的例子复杂一点.因为这种运算是非关联的,它们不是那么容易的能从combiner中获益.中值是将数据集一分为两等份的数 ...

  10. [置顶] 曙光到来,我的新书《Android进阶之光》已出版

    独立博客版本请点击这里 由来 2016年我开始建立了自己的知识体系,所有的文章都是围绕着这个体系来写,随着这个体系的慢慢成长,开始有很多出版社联系我写书,因为比较看好电子工业出版社,就顺理成章的开始了 ...