百分百源码网-让建站变得如此简单! 登录 注册 签到领金币!

主页 | 如何升级VIP | TAG标签

当前位置: 主页>网站教程>数据库> 对于MySQL8.0 InnoDB并行施行的详解
分享文章到:

对于MySQL8.0 InnoDB并行施行的详解

发布时间:09/01 来源:未知 浏览: 关键词:
概述

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;

66ecb3acc5615710de8ab5683f1924a.png

横轴是配置并发线程数,纵轴是语句施行时间。从测试结果来看,整个并行展现还是不错的,扫描2亿笔记录,从单线程的18s,下落到32线程的1s。后面并发开再多,由于数据量有限,多线程的治理耗损超越了并发带来的机能晋升,不克不及再连续缩短SQL施行时间。

MySQL并行施行

实际上当前MySQL的并行施行还处于非常初级阶段,如下图所示,左边是此前MySQL串行处置单个SQL形状;中心的是当前MySQL版本供给的并行能力,InnoDB引擎并行扫描的形状;最右侧的是将来MySQL要开展的形状,优化器按照系统负载和SQL生成并行方案,并将分区方案下发给施行器并行施行。并行施行不仅仅是并行扫描,还包罗并行汇集,并行连接,并行分组,乃至并行排序等。当前版本MySQL的上层的优化器乃至施行器并没有配套的修改。因此,下文的计议主要集中在InnoDB引擎怎样实现并行扫描,主要包罗分区,并行扫描,预读乃至与施行器交互的适配器类。

127da477bbaa6be0639f8d477363759.png

分区

并行扫描的一个中心步骤就是分区,将扫描的数据划分成多份,让多个线程并行扫描。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的并发线程,扫描停止二次分区的状况。

相关代码如下:

2072eee3859cea60f14ba0a382bad65.png

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的会支撑更多并行算子,包罗并行汇集,并行连接,并行分组乃至并行排序等。

以上就是关于MySQL8.0 InnoDB并行施行的详解的具体内容,更多请关注百分百源码网其它相关文章!

打赏

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

百分百源码网 建议打赏1~10元,土豪随意,感谢您的阅读!

共有157人阅读,期待你的评论!发表评论
昵称: 网址: 验证码: 点击我更换图片
最新评论

本文标签

广告赞助

能出一分力是一分吧!

订阅获得更多模板

本文标签

广告赞助

订阅获得更多模板