无论是一次分区,还是二次分区,分区边界的逻辑都一样,以每个分区的最左叶子节点的记录为左下界,并且将这个记录记为相邻上一个分支的右上界。这样确保分区足够多,粒度足够细,充分并行。下图展示了配置为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的会支持更多并行算子,包括并行聚集,并行连接,并行分组以及并行排序等。
以上就是关于MySQL8.0 InnoDB并行执行的详解的详细内容,更多请关注 第一PHP社区 其它相关文章!