概述

MySQL经过多年的发展已然成为最流行的数据库,广泛用于互联网行业,并逐步向各个传统行业渗透。之所以流行,一方面是其优秀的高并发事务处理的能力,另一方面也得益于MySQL丰富的生态。MySQL在处理OLTP场景下的短查询效果很好,但对于复杂大查询则能力有限。最直接一点就是,对于一个SQL语句,MySQL最多只能使用一个CPU核来处理,在这种场景下无法发挥主机CPU多核的能力。MySQL没有停滞不前,一直在发展,新推出的8.0.14版本第一次引入了并行查询特性,使得check table和select count(*)类型的语句性能成倍提升。虽然目前使用场景还比较有限,但后续的发展值得期待。

推荐:《mysql视频教程》

使用方式

通过配置参数innodb_parallel_read_threads来设置并发线程数,就能开始并行扫描功能,默认这个值为4。我这里做一个简单的实验,通过sysbench导入2亿条数据,分别配置innodb_parallel_read_threads为1,2,4,8,16,32,64,测试并行执行的效果。测试语句为select count(*) from sbtest1;

横轴是配置并发线程数,纵轴是语句执行时间。从测试结果来看,整个并行表现还是不错的,扫描2亿条记录,从单线程的18s,下降到32线程的1s。后面并发开再多,由于数据量有限,多线程的管理消耗超过了并发带来的性能提升,不能再继续缩短SQL执行时间。

MySQL并行执行

实际上目前MySQL的并行执行还处于非常初级阶段,如下图所示,左边是之前MySQL串行处理单个SQL形态;中间的是目前MySQL版本提供的并行能力,InnoDB引擎并行扫描的形态;最右边的是未来MySQL要发展的形态,优化器根据系统负载和SQL生成并行计划,并将分区计划下发给执行器并行执行。并行执行不仅仅是并行扫描,还包括并行聚集,并行连接,并行分组,以及并行排序等。目前版本MySQL的上层的优化器以及执行器并没有配套的修改。因此,下文的讨论主要集中在InnoDB引擎如何实现并行扫描,主要包括分区,并行扫描,预读以及与执行器交互的适配器类。

分区

并行扫描的一个核心步骤就是分区,将扫描的数据划分成多份,让多个线程并行扫描。InnoDB引擎是索引组织表,数据以B+tree的形式存储在磁盘上,节点的单位是页面(block/page),同时缓冲池中会对热点页面进行缓存,并通过LRU算法进行淘汰。分区的逻辑就是,从根节点页面出发,逐层往下扫描,当判断某一层的分支数超过了配置的线程数,则停止拆分。在实现时,实际上总共会进行两次分区,第一次是按根节点页的分支数划分分区,每个分支的最左叶子节点的记录为左下界,并将这个记录记为相邻上一个分支的右上界。通过这种方式,将B+tree划分成若干子树,每个子树就是一个扫描分区。经过第一次分区后,可能出现分区数不能充分利用多核问题,比如配置了并行扫描线程为3,第一次分区后,产生了4个分区,那么前3个分区并行做完后,第4个分区至多只有一个线程扫描,最终效果就是不能充分利用多核资源。

二次分区

为了解决这个问题,8.0.17版本引入了二次分区,对于第4个分区,继续下探拆分,这样多个子分区又能并发扫描,InnoDB引擎并发扫描的最小粒度是页面级别。具体判断二次分区的逻辑是,一次分区后,若分区数大于线程数,则编号大于线程数的分区,需要继续进行二次分区;若分区数小于线程数且B+tree层次很深,则所有的分区都需要进行二次分区。

相关代码如下:split_point = 0;

if (ranges.size() > max_threads()) {

//最后一批分区进行二次分区

split_point = (ranges.size() / max_threads()) * max_threads();

} else if (m_depth < SPLIT_THRESHOLD) {

/* If the tree is not very deep then don't split. For smaller tables

it is more expensive to split because we end up traversing more blocks*/

split_point = max_threads();

} else {

//如果B+tree的层次很深(层数大于或等于3,数据量很大),则所有分区都需要进行二次分区

}

无论是一次分区,还是二次分区,分区边界的逻辑都一样,以每个分区的最左叶子节点的记录为左下界,并且将这个记录记为相邻上一个分支的右上界。这样确保分区足够多,粒度足够细,充分并行。下图展示了配置为3的并发线程,扫描进行二次分区的情况。

相关代码如下:

create_ranges(size_t depth, size_t level)

一次分区:

parallel_check_table

add_scan

partition(scan_range, level=0) /* start at root-page */

create_ranges(scan_range, depth=0, level=0)

create_contexts(range, index >= split_point)

二次分区:

split()

partition(scan_range, level=1)

create_ranges(depth=0,level)

并行扫描

在一次分区后,将每个分区扫描任务放入到一个lock-free队列中,并行的worker线程从队列中获取任务,执行扫描任务,如果获取的任务带有split属性,这个时候worker会将任务进行二次拆分,并投入到队列中。这个过程主要包括两个核心接口,一个是工作线程接口,另外一个是遍历记录接口,前者从队列中获取任务并执行,并维护统计计数;后者根据可见性获取合适的记录,并通过上层注入的回调函数处理,比如计数等。

Parallel_reader::worker(size_t thread_id)

{

1.从ctx-queue提取ctx任务

2.根据ctx的split属性,确定是否需要进一步拆分分区(split())

3.遍历分区所有记录(traverse())

4.一个分区任务结束后,维护m_n_completed计数

5.如果m_n_compeleted计数达到ctx数目,唤醒所有worker线程结束

6.根据traverse接口,返回err信息。

}

Parallel_reader::Ctx::traverse()

{

1.根据range设置pcursor

2.找到btree,将游标定位到range的起始位置

3.判断可见性(check_visibility)

4.如果可见,根据回调函数计算(比如统计)

5.向后遍历,若达到了页面的最后一条记录,启动预读机制(submit_read_ahead)

6.超出范围后结束

}

同时在8.0.17版本还引入了预读机制,避免因为IO瓶颈导致并行效果不佳的问题。目前预读的线程数不能配置,在代码中硬编码为2个线程。每次预读的单位是一个簇(InnoDB文件通过段,簇,页三级结构管理,一个簇是一组连续的页),根据页面配置的大小,可能为1M或者2M。对于常见的16k页面配置,每次预读1M,也就是64个页面。worker线程在进行扫描时,会先判断相邻的下一个页面是否为簇的第一个页面,如果是,则发起预读任务。预读任务同样通过lock-free 队列缓存,worker线程是生产者,read-ahead-worker是消费者。由于所有分区页面没有重叠,因此预读任务也不会重复。

执行器交互(适配器)

实际上,MySQL已经封装了一个适配器类Parallel_reader_adapter来供上层使用,为后续的更丰富的并行执行做准备。首先这个类需要解决记录格式的问题,将引擎层扫描的记录转换成MySQL格式,这样做到上下层解耦,执行器不用感知引擎层格式,统一按MySQL格式处理。整个过程是一个流水线,通过一个buffer批量存储MySQL记录,worker线程不停的将记录从引擎层上读上来,同时有记录不停的被上层处理,通过buffer可以平衡读取和处理速度的差异,确保整个过程流动起来。缓存大小默认是2M,根据表的记录行长来确定buffer可以缓存多少个MySQL记录。核心流程主要在process_rows接口中,流程如下

process_rows

{

1.将引擎记录转换成MySQL记录

2.获取本线程的buffer信息(转换了多少mysql记录,发送了多少给上层)

3.将MySQL记录填充进buffer,自增统计m_n_read

4.调用回调函数处理(比如统计,聚合,排序等),自增统计m_n_send

}

对于调用者来说,需要设置表的元信息,以及注入处理记录回调函数,比如处理聚集,排序,分组的工作。回调函数通过设置m_init_fn,m_load_fn和m_end_fn来控制。

总结

MySQL8.0引入了并行查询虽然还比较初级,但已经让我们看到了MySQL并行查询的潜力,从实验中我们也看到了开启并行执行后,SQL语句执行充分发挥了多核能力,响应时间急剧下降。相信在不久的将来,8.0的会支持更多并行算子,包括并行聚集,并行连接,并行分组以及并行排序等。

mysql innodb 并行_关于MySQL8.0 InnoDB并行执行的详解相关推荐

  1. mysql压缩包安装教程8.0.19,win10安装zip版MySQL8.0.19的教程详解

    win10安装zip版MySQL8.0.19的教程详解 一. 下载后解压到想安装的目录 二. 在安装目录中添加配置文件my.ini [mysqld] # 设置3306端口 port=3306 # 设置 ...

  2. linux下安装mysql_Linux下安装mysql-8.0.20的教程详解

    ** Linux下安装mysql-8.0.20 ** 环境介绍 操作系统:CentOS 7 mysql下载地址:https://dev.mysql.com/downloads/mysql/ 下载版本: ...

  3. mysql8.0.20安装教程linux_Linux下安装mysql-8.0.20的教程详解

    ** Linux下安装mysql-8.0.20 ** 环境介绍 操作系统:CentOS 7 mysql下载地址:https://dev.mysql.com/downloads/mysql/ 下载版本: ...

  4. mysql在线主从复制_使用MySQL8.0 clone技术在线搭建主从复制

    MySQL从8.0.17开始新增了克隆clone技术,可以在线进行MySQL的本地克隆或远程克隆,从此搭建从库可以不再需要备份工具来实现了,下面将通过clone来实现一个远程从库的搭建:环境如下 Ma ...

  5. mysql分区并行执行_关于MySQL8.0 InnoDB并行执行的详解

    概述 MySQL经过多年的发展已然成为最流行的数据库,广泛用于互联网行业,并逐步向各个传统行业渗透.之所以流行,一方面是其优秀的高并发事务处理的能力,另一方面也得益于MySQL丰富的生态.MySQL在 ...

  6. 大商创MySQL不支持_大商创配置文件config.php详解

    大商创配置文件config.php在data目录下,config.php配置文件主要用于配置数据库.//database host $db_host = "localhost:3306&qu ...

  7. linux编写驱动后write已杀死_《Linux4.0设备驱动开发详解》笔记--第九章:Linux设备驱动中的异步通知与同步I/O...

    在设备驱动中使用异步通知可以使得对设备的访问可进行时,由驱动主动通知应用程序进行访问.因此,使用无阻塞I/O的应用程序无需轮询设备是否可访问,而阻塞访问也可以被类似"中断"的异步通 ...

  8. android分屏模式_安卓 7.0 分屏功能详解:三种模式,想分就分

    IT之家讯 8月18日消息,安卓7.0的一大特色就是自带全新分屏功能,分为多画面显示模式.画中画模式和自由分屏模式三种,本文将详细介绍这三种模式. 多画面显示模式 启动该模式的方法有两种,一是在后台应 ...

  9. mysql 邻接表_图的邻接表存储结构详解

    通常,图更多的是采用链表存储,具体的存储方法有 3 种,分别是邻接表.邻接多重表和十字链表. 本节先讲解图的邻接表存储法.邻接表既适用于存储无向图,也适用于存储有向图. 在具体讲解邻接表存储图的实现方 ...

最新文章

  1. php+php-fom+nginx配置参数调优详解
  2. 互联网工作原理(17.网络电视是如何工作的)
  3. 最全三大框架整合(使用映射)——applicationContext.xml里面的配置
  4. 三个世界及其有关概念
  5. cookie工作流程
  6. c#获取Windows Mobile短信
  7. mathquill web公式编辑器 总结 、实列、 源码
  8. GRE高频词汇出现频率汇总
  9. ORACLE表空间和表碎片分析及整理方法
  10. android 考勤界面,一种android终端实时考勤记录统计展现方法和装置与流程
  11. windows7 安装pytorch简易教程
  12. linux上咋修复windows引导,linux rescue 修复引导 与linux下修复windows引导
  13. html5 游戏制作教程,利用HTML5 Canvas制作一个简单的打飞机游戏
  14. 创新设计思维记录(part1)
  15. python html 补全标签_补充:HTML标签和CSS
  16. Mysql出租车轨迹的分析_一种基于出租车轨迹数据的交通出行共现现象的可视化分析方法与流程...
  17. 高德地图的基础使用(一)显示地图
  18. 计算机专业选锐龙还是英特尔,还在纠结锐龙还是英特尔吗?送你一份CPU选购指南...
  19. 离散制造,重复制造和流程制造总结
  20. 软件定义数据中心(SDDC)的日志分析

热门文章

  1. linux 用户/用户组添加修改删除(ubuntu/centos)
  2. ArcMap中的名称冲突问题
  3. android中OnItemClickListener的参数解释
  4. OpenCv cv::Mat 转 IplImage 函数
  5. 8月第一周国内搜索网站 排名顺序基本稳定
  6. C# 使用Win32 API模拟键盘鼠标操作网页
  7. JavaWeb学习总结(三十五)——使用JDBC处理Oracle大数据
  8. GridView中FooterTemplate模板下内容不显示
  9. 手把手教你如何用Python制作一个电子相册?末附python教程
  10. ElasticJob corn定时表达式语法(亲测)