请选择 进入手机版 | 继续访问电脑版

从库数据查找和参数slave_rows_search_algorithms

[复制链接]
滚雪球少年 发表于 2020-12-31 18:57:09 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
导读:
  
  本文节选自八怪专栏《深入明白MySQL主从原理32讲》第24节
想阅读更多内容请点击订阅专栏

注意:如果正文有图片不清晰可以将图片生存到当地查察(本文发起横屏观看效果更佳)
  
本节包罗一个笔记如下:https://www.jianshu.com/p/5183fe0f00d8
我们前面已经知道了对于DML语句来讲其数据的更改将被放到对应的Event中。比如‘Delete’语句会将所有删除数据的before_image放到DELETE_ROWS_EVENT中,从库只要读取这些before_image举行数据查找,然后调用相应的‘Delete’的操纵就可以完成数据的删除了。下面我们来讨论一下从库是如何举行数据查找的。
本节我们假定参数binlog_row_image设置为‘FULL’也就是默认值,关于binlog_row_image参数的影响在第11节已经形貌过了。
一、从一个列子出发

在开始之前我们先假定参数‘slave_rows_search_algorithms’为默认值,即:


  • TABLE_SCAN,INDEX_SCAN
因为这个参数会直接影响到对索引的利用方式。
我们照旧以‘Delete’操纵为例,实际上对于索引的选择‘Update’操纵也是一样的,因为都是通过before_image去查找数据。我测试的表布局、数据和操纵如下:
  1. mysql> show create table tkkk \G*************************** 1. row ***************************       Table: tkkkCreate Table: CREATE TABLE `tkkk` (  `a` int(11) DEFAULT NULL,  `b` int(11) DEFAULT NULL,  `c` int(11) DEFAULT NULL,  KEY `a` (`a`)) ENGINE=InnoDB DEFAULT CHARSET=utf81 row in set (0.00 sec)mysql> select * from tkkk;+------+------+------+| a    | b    | c    |+------+------+------+|    1 |    1 |    1 ||    2 |    2 |    2 ||    3 |    3 |    3 ||    4 |    4 |    4 ||    5 |    5 |    5 ||    6 |    6 |    6 ||    7 |    7 |    7 ||    8 |    8 |    8 ||    9 |    9 |    9 ||   10 |   10 |   10 ||   11 |   11 |   11 ||   12 |   12 |   12 ||   13 |   13 |   13 ||   15 |   15 |   15 ||   15 |   16 |   16 ||   15 |   17 |   17 |+------+------+------+16 rows in set (2.21 sec)mysql> delete from tkkk where a=15;Query OK, 3 rows affected (6.24 sec)因为我做了debug索引这里时间看起来很长
复制代码
对于这样一个‘Delete’语句来讲主库会利用到索引 KEY a,删除的三条数据我们实际上只需要一次索引的定位(参考btr_cur_search_to_nth_level函数),然后顺序扫描接下来的数据举行删除就可以了。大概的流程如下图:

这条数据删除的三条数据的before_image将会记载到一个DELETE_ROWS_EVENT中。从库应用的时候会重新评估应该使用哪个索引,优先使用主键和唯一键。对于Event中的每条数据都需要举行索引定位操纵,而且对于非唯一索引来讲第一次返回的第一行数据大概并不是删除的数据,还需要需要继续扫描下一行,在函数Rows_log_event::do_index_scan_and_update中有如下代码:
  1. while (record_compare(m_table, &m_cols))//比力每一个字段 如果不相等 扫描下一行  {    while((error= next_record_scan(false)))//扫描下一行    {      /* We just skip records that has already been deleted */      if (error == HA_ERR_RECORD_DELETED)        continue;      DBUG_PRINT("info",("no record matching the given row found"));      goto end;    }  }
复制代码
这些代价是比主库更大的。在这个列子中没有主键和唯一键,因此依旧使用的是索引KEY a,大概流程如下图:

但是如果我们在从库增加一个主键,那么在从库举行应用的时候流程如下:

我们从上面的流程来看,主库‘Delete’操纵和从库‘Delete’操纵主要的区别在于:


  • 从库每条数据都需要索引定位查找数据。
  • 从库在某些情况下通过非唯一索引查找的数据第一条数据大概并不是删除的数据,因此还需要继续举行索引定位和查找。
对于主库来讲一般只需要一次数据定位查找即可,接下来访问下一条数据就好了。实在对于真正的删除操纵来讲并没有太多的区别。如果公道的使用了主键和唯一键可以将上面提到的两点影响低沉。在造成从库延迟的情况中,没有公道的使用主键和唯一键是一个比力重要的原因。
最后如果表上一个索引都没有的话,那么情况变得更加严重,简单的图如下:

我们可以看到每一行数据的更改都需要举行全表扫描,这种问题就非常严重了。这种情况使用参数‘slave_rows_search_algorithms’的HASH_SCAN选项也许可以提高性能,下面我们就来举行讨论。
二、确认查找数据的方式

前面的例子中我们打仗了参数‘slave_rows_search_algorithms’,这个参数主要用于确认如何查找数据。其取值可以是下面几个组合(来自官方文档),源码中体现为一个位图:


  • TABLE_SCAN,INDEX_SCAN(默认值)
  • INDEX_SCAN,HASH_SCAN
  • TABLE_SCAN,HASH_SCAN
  • TABLE_SCAN,INDEX_SCAN,HASH_SCAN
在源码中有如下的说明,当然官方文档也有类似的说明:
  1.   /*    Decision table:    - I  --> Index scan / search    - T  --> Table scan    - Hi --> Hash over index    - Ht --> Hash over the entire table    |--------------+-----------+------+------+------|    | Index\Option | I , T , H | I, T | I, H | T, H |    |--------------+-----------+------+------+------|    | PK / UK      | I         | I    | I    | Hi   |    | K            | Hi        | I    | Hi   | Hi   |    | No Index     | Ht        | T    | Ht   | Ht   |    |--------------+-----------+------+------+------|  */
复制代码
实际上源码中会有三种数据查找的方式,分别是:


  • ROW_LOOKUP_INDEX_SCAN
对应函数接口:Rows_log_event::do_index_scan_and_update


  • ROW_LOOKUP_HASH_SCAN
对应函数接口:Rows_log_event::do_hash_scan_and_update


  • ROW_LOOKUP_TABLE_SCAN
对应函数接口:Rows_log_event::do_table_scan_and_update
在源码中如下:
  1. switch (m_rows_lookup_algorithm)//根据差异的算法决定使用哪个方法    {      case ROW_LOOKUP_HASH_SCAN:        do_apply_row_ptr= &Rows_log_event::do_hash_scan_and_update;        break;      case ROW_LOOKUP_INDEX_SCAN:        do_apply_row_ptr= &Rows_log_event::do_index_scan_and_update;        break;      case ROW_LOOKUP_TABLE_SCAN:        do_apply_row_ptr= &Rows_log_event::do_table_scan_and_update;        break;
复制代码
决定如何查找数据以及通过哪个索引查找正是通过参数‘slave_rows_search_algorithms’的设置和表中是否有符合的索引共同决定的,并不是完全由‘slave_rows_search_algorithms’参数决定。
下面这个图就是决定的过程,可以参考函数decide_row_lookup_algorithm_and_key(如下图)。

三、ROW_LOOKUP_HASH_SCAN方式的数据查找

总的来讲这种方式和ROW_LOOKUP_INDEX_SCAN和ROW_LOOKUP_TABLE_SCAN都差异,它是通过表中的数据和Event中的数据举行比对,而不是通过Event中的数据和表中的数据举行比对,下面我们将详细形貌这种方法。
假设我们将参数‘slave_rows_search_algorithms’设置为INDEX_SCAN,HASH_SCAN,且表上没有主键和唯一键的话,那么上图的流程将会把数据查找的方式设置为ROW_LOOKUP_HASH_SCAN。
在ROW_LOOKUP_HASH_SCAN又包罗两种数据查找的方式:


  • Hi --> Hash over index
  • Ht --> Hash over the entire table
对于ROW_LOOKUP_HASH_SCAN来讲,其首先会将Event中的每一行数据读取出来存入到HASH布局中,如果可以或许使用到Hi那么还会额外维护一个集合(set),将索引键值存入集合,作为索引扫描的依据。如果没有索引这个集合(set)将不会维护直接使用全表扫描,即Ht。
需要注意一点这个过程的单位是Event,我们前面说过一个DELETE_ROWS_EVENT大概包罗了多行数据,Event最大为8K左右。因此使用Ht --> Hash over the entire table的方式,将会从原来的每行数据举行一次全表扫描变为每个Event才举行一次全表扫描
但是对于Hi --> Hash over index来讲效果就没有那么显着了,因为如果删除的数据重复值很少的情况下,依然需要足够多的索引定位查找才行,但是如果删除的数据重复值较多那么构造的集合(set)元素将会大大减少,也就减少了索引查找定位的开销。
思量别的一种情况,如果我的每条delete语句一次只删除一行数据而不是delete一条语句删除大量的数据,那这种情况每个DELETE_ROWS_EVENT只有一条数据存在,那么使用ROW_LOOKUP_HASH_SCAN方式并不会提高性能,因为这条数据照旧需要举行一次全表扫描或者索引定位才华查找到数据,和默认的方式没什么区别。
整个过程参考如下接口:


  • Rows_log_event::do_hash_scan_and_update:总接口,调用下面两个接口。
  • Rows_log_event::do_hash_row:将数据加入到hash布局,如果有索引还需要维护集合(set)。
  • Rows_log_event::do_scan_and_update:查找而且举行删除操纵,会调用Rows_log_event::next_record_scan举行数据查找。
  • Rows_log_event::next_record_scan:详细的查找方式实现了Hi --> Hash over index和Ht --> Hash over the entire table的查找方式
下面我们照旧用最开始的列子,我们删除了三条数据,因此DELETE_ROW_EVENT中包罗了三条数据。假设我们参数‘slave_rows_search_algorithms’设置为INDEX_SCAN,HASH_SCAN。因为我的表中没有主键和唯一键,因此会最终使用ROW_LOOKUP_HASH_SCAN举行数据查找。但是因为我们有一个索引key a,因此会使用到Hi --> Hash over index。为了更好的形貌Hi和Ht两种方式,我们也假定另一种情况是表上一个索引都没有,我将两种方式放到一个图中方便各人发现差异点,如下图:

四、总结

我记得以前有位朋友问我主库没有主键如果我在从库创建一个主键能低沉延迟吗?这里我们就清楚了答案是肯定的,因为从库会根据Event中的行数据举行使用索引的选择。那么总结一下:


  • slave_rows_search_algorithms参数设置了HASH_SCAN并不一定会提高性能,只有满足如下两个条件才会提高性能:
  • 从库索引的利用是自行判定的,顺序为主键->唯一键->普通索引。
  • 如果slave_rows_search_algorithms参数没有设置HASH_SCAN,而且没有主键/唯一键那么性能将会急剧下降造成延迟。如果连索引都没有那么这个情况更加严重,因为更改的每一行数据都会引发一次全表扫描。
因此我们发现在MySQL中强制设置主键又多了一个来由。


识别下方二维码添加作者为挚友

END
  
点击下图小步伐订阅
《深入明白MySQL主从原理32讲》专栏
可了解更多八怪技术文章










扫码加入MySQL技术Q群



(群号:529671799)
   






来源:https://blog.csdn.net/n88Lpo/article/details/100144083
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则


专注素材教程免费分享
全国免费热线电话

18768367769

周一至周日9:00-23:00

反馈建议

27428564@qq.com 在线QQ咨询

扫描二维码关注我们

Powered by Discuz! X3.4© 2001-2013 Comsenz Inc.( 蜀ICP备2021001884号-1 )