专栏首页MySQL内核Myrocks基本查询源码
原创

Myrocks基本查询源码

Myrocks是Percona在MySQL上接入了Rocksdb引擎的产物,接入新引擎的主要修改的地方就是MySQL的handler接口。以下针对常用的几个查询分析Myrocks是如何进行处理的。设有表 t1(a INT, b INT)

a

b

1

1

2

2

3

3

4

4

t2(a INT PRIMARY KEY, b INT, INDEX(b))

a

b

1

1

2

2

3

3

4

4

t3(a INT PRIMARY KEY, b INT, c INT, INDEX(b))

a

b

c

1

1

1

2

2

2

3

3

3

4

4

4

0.共用栈

|-mysql_parse()
|--mysql_execute_command()
|---Sql_cmd_dml::execute()
|----Sql_cmd_dml::execute_inner()

1.基于主键的点查询

这种情况是最特殊的一种,基于主键的点查询只需要和Rocksdb引擎交互一次,找到主键也就找到了所需要的数据。 如 SELECT * FROM t2 WHERE a = 2;

|-SELECT_LEX::optimize()
|--JOIN::optimize()
|---JOIN::make_join_plan()
|----JOIN::extract_func_dependent_tables()
|-----join_read_const_table()
|------read_const()
----------------------
|-handler::ha_index_read_idx_map()
|--handler::index_read_idx_map()
|---ha_rocksdb::index_read_map()
/* key = 2,需要构造slice */
|----ha_rocksdb::index_read_map_impl() /* 判断是否基于主键查询 */
|-----ha_rocksdb::get_row_by_rowid()

如果没有主键(如t1)的话,rocksdb也是会为每行数据创建一个rowid作为主键,实际上,不管有没有用户自定义主键,每张表上都是有主键的,只是显式和隐式的区别。

2.全表扫描

全表扫描需要借助迭代器来完成,所以再初始化扫描的过程中需要初始化迭代器。 如SELECT * FROM t1;

|-JOIN::exec()
|--do_select()
|---sub_select()
|----TableScanIterator::Init()
|-----handler::ha_rnd_init()
|------ha_rocksdb::rnd_init()
/* 这里需要调用成员m_pk_descr的get_first_key方法来确定迭代器的初始位置 */
/* successor()/predecessor()分别计算处于当前key的下一个key和上一个key */
|-------ha_rocksdb::setup_iterator_for_rnd_scan()
|--------Seek() /* rocksdb方法,具体定位数据 */
|----TableScanIterator::Read()
|-----handler::ha_rnd_next()
|------ha_rocksdb::rnd_next()
/* 根据方向进行迭代,rocksdb提供next和prev两种方式。这里拿出KV进行处理(decode等) */
|-------ha_rocksdb::rnd_next_with_direction()
|-----handler::ha_index_or_rnd_end()
|------handler::ha_rnd_end()
|-------ha_rocksdb::rnd_end()

这里有一种特殊情况,当表t只有两列(a primary key,b index key)时,执行全表扫描会通过二级索引进行查询。当然,这里通过二级索引进行查询并不会走'二级索引->主键->数据'的路子,因为只有两列数据,查询二级索引获取主键的过程中已经获得了全部数据,因此不用再通过主键去查询完整的数据。理论上这种形式和直接查主键时等价的,之所以会通过二级索引因该与优化器的实现有关。如SELECT * FROM t2;

3.基于主键的范围查询

范围查询分三种情况 x > a; x < a; a < x < b;其中第三种情况最好处理,因为start_key和end_key已知,另外两种情况只知其一(实际上也没有什么大的差别) 如SELECT * FROM t2 WHERE a < 3;

|-JOIN::init_planner_arrays()
|--TABLE_LIST::fetch_number_of_rows()
|---ha_rocksdb::info()
|----ha_rocksdb::get_range()
|-IndexRangeScanIterator::Read()
|--QUICK_RANGE_SELECT::get_next()
|---handler::ha_multi_range_read_next()
|----handler::multi_range_read_next()
/* 这里会传入start_key/end_key,如果start_key为空,
   就通过索引(这里是主键)查找出第一行符合要求的数据构造start_key
   ha_index_first(),在上述例子中就是找到key=1作为start_key
   end_key为空没有什么关系,我们可以一直读到下一个不符合要求的key为止
*/
|-----ha_rocksdb::read_range_first()
//rocksdb查询方式:storage/rocksdb/rocksdb-range-access.txt
/* 这里面有和循环来读取范围内的数据
   1.移动到正确的初始位置position_to_correct_key()
   2.验证是否使用布隆过滤并设置查询的上下边界ha_rocksdb::check_bloom_and_set_bounds()
   3.注意:这里设置的lower_bound或upper_bound其实是key+1或key-1,所以这两个bound之间差2
   4.构建的lower_bound/upper_bound当然是经过编码的
*/
|------ha_rocksdb::index_read_map_impl()
|-------ha_rocksdb::setup_scan_iterator()
|--------ha_rocksdb::check_bloom_and_set_bounds()

4.基于二级索引的查询

基于二级索引的点查询或范围查询与上述过程是类似的,只是多了一次通过主键回查完整数据的调用(2中所述的特殊情况除外) 如SELECT * FROM t3 WHERE b = 2;

/* 过程有省略 */
|-RefIterator<false>::Read()
|--handler::ha_index_read_map()
|---ha_rocksdb::index_read_map()
|----ha_rocksdb::index_read_map_impl()
|-----ha_rocksdb::read_row_from_secondary_key()
|------ha_rocksdb::get_row_by_rowid()

以t3为例,相较2/3,多的是read_row_from_secondary_key()这一个调用。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 动手创建自己的存储引擎(〇)

    MySQL插件式的存储引擎是其突出的特色之一,像InnoBD/MyISAM之类的存储引擎都是插件式的存储引擎。为了适应各种不同的需求,我们自己也可以动手创建自己...

    devsql
  • 动手创建自己的存储引擎(一)

    初始化一个存储引擎实现起来非常简单,因为MySQL已经为我们准备了一个十分好用的模板example引擎。

    devsql
  • MySQL8.0数据字典实现一窥

    Dictionary_client是整个数据字典的客户端,用户对于数据字典的操作都是通过该client实现的。

    devsql
  • 本周热点事件盘点

    01 本周热点事件盘点 1.澳大利亚政府发布小型企业网络安全指南 【关键字:企业安全】 近日,澳大利亚政府小型企业与家族企业监察专员组(ASBFEO)发布了小型...

    安恒信息
  • mysql 索引 键 主键 外键等概念彻底理清楚

    参考文章: Mysql 索引详解和优化 数据库原理-几种数据模型 Mysql中的key和index的区别 (讲的很合理) Mysql中的Casc...

    waki
  • [日常] MySQL的预处理技术测试

    MySQL预处理技术: 1.减轻服务器压力 2.防止sql注入,把传递过去的危险字符也只当做参数处理 3.将sql语句强制一分为二:第一部分为前面相同的命令和结...

    陶士涵
  • Hopfield网络及其收敛性

    在上一次的神经网络之双向关联记忆网络(BAM)中我们介绍了神经网络中能量的概念。在BAM的基础上稍加改变就可以得到著名的Hopfield网络。

    史博
  • R.python常见问题①(不常见的安装包bug)

    如上图所示:在Rgui和Rstudio中都遇到了一个问题,使用install.packages()出现错误,阅读error发现是无法连接到镜像的包集合中。其大概...

    用户1359560
  • ​C++ STL源码剖析之unordered_xxx

    前面学到了hashtable,而这节是hashtable的容器适配器:unordered_map。

    公众号guangcity
  • vue学习笔记11-自定义指令

    除了默认设置的核心指令( v-model 和 v-show ), Vue 也允许注册自定义指令。 注册指令的关键字是directive, 同样也有局部和全局之分...

    雪地二货

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动