> 文档中心 > MySQL8.0 InnoDB并行查询特性

MySQL8.0 InnoDB并行查询特性

概述

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

使用方式

通过配置参数 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 tablesit 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记录。核心流程主要在p rocess_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的会支持更多并行算子,包括并行聚集,并行连接,并行分组以及并行排序等。

今天为大家准备了互联网面试必备的1到5年Java面试者都需要掌握的面试题,分别JVM,并发编程,MySQL,Tomcat,网络与IO及Spring系列等等,可以说掌握这些薪资涨10K还是可以的!

 

今天分享给大家的都是目前主流企业使用最高频的面试题库,也都是 Java 版本升级之后,重新整理归纳的最新答案,会让面试者少走很多不必要的弯路。同时每个专题都做到了详尽的面试解析文档,以确保每个阶段的读者都能看得懂。

Java虚拟机26题

  1.     

  2. JDK、 JRE、JVM 的关系是什么?     

  3. JVM 的内存模型以及分区情况和作用     

  4. JVM 对象创建步骤流程是什么?     

  5. 垃圾回收算法有几种类型? 他们对应的优缺点又是什么?     

  6. 简单介绍一下什么是类加载机制?     

  7. 类的加载过程是什么?简单描述一下每个步骤     

  8. JVM 预定义的类加载器有哪几种?分别什么作用?     

  9. 什么是双亲委派模式?有什么作用?     

  10. 什么是 Class 文件? Class 文件主要的信息结构有哪些?     

  11. 对象“对象已死” 是什么概念?     

  12. Java 语言怎么实现跨平台的?     

  13. JVM 数据运行区,哪些会造成 OOM 的情况?     

  14. 详细介绍一下对象在分带内存区域的分配过程?     

  15. G1 与 CMS 两个垃圾收集器的对比     

  16. 线上常用的 JVM 参数有哪些?     

  17. 对象什么时候进入老年代?     

  18. 什么是内存溢出, 内存泄露? 他们的区别是什么?     

  19. 引起类加载操作的行为有哪些?     

  20. 介绍一下 JVM 提供的常用工具     

  21. Full GC 、 Major GC 、Minor GC 之间区别?     

  22. 什么时候触发 Full GC ?     

  23. 什么情况下会出现栈溢出     

  24. 说一下强引用、软引用、弱引用、虚引用以及他们之间和 gc 的关系     

  25. Eden 和 Survivor 的比例分配是什么情况?为什么?     

  26. CPU 资源占用过高怎么办     

  27. OOM 异常排查

同时里面还有我整理的JVM学习笔记和学习路线导图,很详尽的讲解了JVM的学习内容和实战笔记,有需要的朋友可观注下方公众号

内容分为五6个模块

  •     

  • JVM内存区 域划分     

  • JVM执行子系统     

  • 垃圾回收器和内存分配策略     

  • 编写高效优雅Java程序     

  • 性能优化     

  • JVM与性能优化学习笔记.Xmind

Java并发编程25题

  1.     

  2. Synchronized用过吗,其原理是什么?     

  3. 你刚才提到获取对象的锁,这个“锁”到底是什么?如何确定对象的锁     

  4. 什么是可重入性,为什么说Synchronized是可重入锁?     

  5. JVM对Java的原生锁做了哪些优化?     

  6. 为什么说Synchronized是非公平锁?     

  7. 什么是锁消除和锁粗化?     

  8. 为什么说Synchronized是一个悲观锁? 乐观锁的实现原理又是什么?什么是CAS?     

  9. 乐观锁一定就是好的吗?     

  10. 跟Synchronized相比,可重入锁Reentrantl ock其实现原理有什么不同?     

  11. 那么请谈谈AQS框架是怎么回事儿?     

  12. 请尽可能详尽地对比下Synchronized和ReentrantLock的异同。     

  13. Reentrantl ock是如何实现可重入性的?     

  14. 除了ReetrantLock, 你还接触过JUC中的哪些并发工具?     

  15. 请谈谈ReadWriteLock和StampedLock如何让Java的线程彼此同步?你了解过哪些同步器?请分别介绍下     

  16. CyclicBarrier和CountDownLatch看起来很相似,请对比下呢?

对于并发编程这一块小编只展示了15题,分为5个模块,这些可以是大厂一面二面百分90%都问到的问题

MySQL数据库20题

目录展示

针对这20道高频问题,做出了很详细的解析,同时对MySQL及优化这一块而言,在这有一份笔记导图,里面每个节点都有笔记记载!

网络20题

  1.     

  2. HTTP 响应码有哪些?分别代表什么含义?     

  3. Forward 和 Redirect 的区别?     

  4. 如何实现跨域?     

  5. 说一下 JSONP 实现原理?     

  6. get 和 post 请求有哪些区别?     

  7. 简述 TCP 和 UDP 的区别?     

  8. TCP 为什么要三次握手,两次不行吗?为什么?     

  9. 说一下 TCP 粘包是怎么产生的?怎么解决粘包问题的?     

  10. TCP 如何保证可靠性     

  11. 拥塞控制与流量控制的区别?     

  12. OSI 的七层模型都有哪些?     

  13. 网络浏览器访问一个网址的整个过程?     

  14. 解释滑动窗口算法     

  15. 域名解析详细过程     

  16. IP 地址分为几类,每类都代表什么,私网是哪些?     

  17. 计算机网络中的同步和异步     

  18. 发现百度上不去,怎么办?     

  19. Cookie 和 Session 的区别?     

  20. HTTP 1.0 和 1.1 的区别?     

  21. HTTP 和 HTTPS 的主要区别?

Spring系列100题

  1.     

  2. 什么是Spring框架? Spring框架有哪些主要模块?     

  3. 使用Spring框架能带来哪些好处?     

  4. 什么是控制反转(IOC)?什么是依赖注入?     

  5. 请解释下Spring框架中的loC?     

  6. BeanFactory 和ApplicationContext有什么区别?     

  7. Spring 有几种配置方式?     

  8. 如何用基于XML配置的方式配置Spring?     

  9. 如何用基于Java配置的方式配置Spring?     

  10. 怎样用注解的方式配置Spring?     

  11. 请解释Spring Bean的生命周期?     

  12. Spring Bean的作用域之间有什么区别?     

  13. 什么是Spring inner beans?     

  14. Spring 框架中的单例Beans是线程安全的么?     

  15. 请举例说明如何在Spring中注入一个Java Collection?     

  16. 如何向Spring Bean中注入一个Java.util.Properties?     

  17. 请解释Spring Bean的自动装配?     

  18. 请解释自动装配模式的区别?     

  19. 如何开启基于注解的自动装配?     

  20. 请举例解释@Required 注解?     

  21. 请举例解释@ Autowired注解?     

  22. 构造方法注入和设值注入有什么区别?     

  23. Spring 框架中有哪些不同类型的事件?     

  24. FileSystemResource 和ClassPathResource有何区别?     

  25. Spring 框架中都用到了哪些设计模式?

针对Spring系列问题只展示了24题,剩下的关于SpringBoot,Spring Cloud等问题也做出了很详细的解析,同时还有25节视频讲解Spring源码!

由于资料内容太多,平台篇幅限制,小编就展现了以上部分面试专题与资料,如需获取以下全部面试资料的同学,获取方式在下方公众号感谢配合与信任!

福利再附赠:498页Java架构进阶面试解析笔记内容涵盖包括(Java、MyBatis、ZooKeeper、Dubbo、Redis、MySQL、Spring、Spring Boot、Spring Cloud、RabbitMQ、Kafka、Linux 等等,)希望大家都能找到适合自己的公司,开开心心的撸代码。

天天排行榜