innodb并行查询

概述

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

使用

通过配置参数innodb_parallel_read_threads来设置并发线程数,就能开始并行扫描功能,默认值为4,innodb_parallel_read_threads是 session 级别的变量。

set local innodb_parallel_read_threads=4;

select count(*) from sbtest.table;

设计思想

Parallel read of index 主要利用当前的多核硬件优势, 针对当前可以并行读取的逻辑例如 SELECT COUNT() 或者 CHECK TABLE, 其主要逻辑是收集数据叶子节点的 Page Number, 使用多个 worker 并行读取数据 Page, 利用不同的回调函数来处理获取后的 rows. 目前 SELET COUNT() 和 CHECK TABLE 都是同步读取

实现

row_scan_index_for_mysql()

/* 扫描索引数据 */

row_scan_index_for_mysql()
/* SELECT COUNT() */
------------------------------
–> parallel_select_count_star()
------------------------------
/* CHECK TABLE */
------------------------
–> parallel_check_table()
基本数据结构

Parallel_reader::Scan_range: 代表当前并行扫描的范围.

Parallel_reader::Config 并行扫描的 configuration.

Parallel_reader::Scan_ctx 并行扫描的上下文 (context).

Parallel_reader::Ctx 并行读取的执行上下文 (Parallel reader execution context)

Parallel_reader 并行扫描 reader

SELECT COUNT()

我们以全表扫描 SELECT COUNT() 为例, 根据源码分析 Parallel Read 的原理:

/* SELECT COUNT() 的入口函数 */

static dberr_t parallel_select_count_star(Key_reader &reader, ulint *n_rows) {
  Counter::Shards n_recs;

  Counter::clear(n_recs);

  const buf_block_t *prev_block = nullptr;

  dberr_t err =
      reader.read([&](size_t id, const buf_block_t *block, const rec_t *rec,
                      dict_index_t *index, row_prebuilt_t *prebuilt) {
        Counter::inc(n_recs, id);

        /* Only check the THD state for the first thread. */
        if (id == 0 && block != prev_block) {
          prev_block = block;
          if (trx_is_interrupted(reader.trx())) {
            return (DB_INTERRUPTED);
          }
        }

        return (DB_SUCCESS);
      });

  /* 统计计数 */
  *n_rows = Counter::total(n_recs);

  return (err);
}

Key_reader 使用 partition() 将 B+ tree 分片, 分配各个 worker 线程, InnoDB 的 B+ 树将数据存放在所有的叶子节点, 即叶子节点为 level 0, 分配策略是从 root 节点遍历, 使用 left_leaf() 从左边由上至下直到 level N 层的节点数量大于等于 worker 线程数量:
并行读取流程

并行读取流程

启动 worker 线程, worker 线程也就是真正的读取线程,对一个切好的 sub-tree 做 scan, worker 线程分别根据被分配的 leaf page cursor 进行顺序读取.
并行读取线程会根据创建的读取对应叶子节点的 record, 并且会根据 trx->read_view 来判断可见性.

  • 25
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值