[MySQL 5.6] 5.6新参数slave_rows_search_algorithms

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:

我们知道,MySQL有一个老问题,当表上无主键时,那么对于在该表上做的DML,如果是以ROW模式复制,则每一个行记录前镜像在备库都可能产生一次全表扫描(或者二级索引扫描),大多数情况下,这种开销都是非常不可接受的,并且产生大量的延迟。


在MySQL5.6中提供了一个新的参数:slave_rows_search_algorithms, 可以部分解决无主键表导致的复制延迟问题,其基本思路是对于在一个ROWS EVENT中的所有前镜像收集起来,然后在一次扫描全表时,判断HASH中的每一条记录进行更新。


测试:


首先来看看性能怎么样,我们使用sbtest表,并将其上面的主键及二级索引全部删除,表中有200万行数据

主库执行随机更新操作:

     update table sbtest2 set k = k +15 order by rand() limit  [$RECOR_NUM]; 

备库的最大延迟时间(基本等同执行时间)如下:

随机更新记录数

TABLE_SCAN,INDEX_SCAN

TABLE_SCAN,INDEX_SCAN,HASH_SCAN

10

26s

6s

20

51s

9s

40

96s

15s

60

147s

25s

80

187s

30s

100

228s

37s

可以看出来,该特性对于无主键表的复制延迟问题,还是有很大的帮助的。

如何使用:

slave_rows_search_algorithms的文档描述的非常清晰,该变量由三个值的组合组成:TABLE_SCAN,INDEX_SCAN, HASH_SCAN,使用组合包括:

TABLE_SCAN,INDEX_SCAN  (默认配置,表示如果有索引就用索引,否则使用全表扫描)

INDEX_SCAN,HASH_SCAN

TABLE_SCAN,HASH_SCAN

TABLE_SCAN,INDEX_SCAN,HASH_SCAN(等价于INDEX_SCAN, HASH_SCAN)

参数组合(摘自log_event.cc: 9633~9648)

  /*
    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   |
    |--------------+-----------+------+------+------|

  */

实现:

a.决定使用哪种scan方式:

函数:Rows_log_event::decide_row_lookup_algorithm_and_key

调用backtrace:

Rows_log_event::do_apply_event

     ->do_before_row_operations

          ->Rows_log_event::row_operations_scan_and_key_setup

                    ->Rows_log_event::decide_row_lookup_algorithm_and_key 

没啥好说的,根据上述的参数组合矩阵,来确定使用哪种scan策略,存储在rows log event对象的m_rows_lookup_algorithm中

另外这里也会去看看是否能够使用索引,以及使用哪个索引(this->m_key_index= search_key_in_table),

b.执行过程

在函数Rows_log_event::do_apply_event中,当确定了使用哪种scan策略后,就可以选择对应的接口函数:

11084     switch (m_rows_lookup_algorithm)
11085     {
11086       case ROW_LOOKUP_HASH_SCAN:
11087         do_apply_row_ptr= &Rows_log_event::do_hash_scan_and_update;
11088         break;
11089
11090       case ROW_LOOKUP_INDEX_SCAN:
11091         do_apply_row_ptr= &Rows_log_event::do_index_scan_and_update;
11092         break;
11093
11094       case ROW_LOOKUP_TABLE_SCAN:
11095         do_apply_row_ptr= &Rows_log_event::do_table_scan_and_update;
11096         break;
11097
11098       case ROW_LOOKUP_NOT_NEEDED:
11099         DBUG_ASSERT(get_general_type_code() == WRITE_ROWS_EVENT);
11100
11101         /* No need to scan for rows, just apply it */
11102         do_apply_row_ptr= &Rows_log_event::do_apply_row;
11103         break;
11104
11105       default:
11106         DBUG_ASSERT(0);
11107         error= 1;
11108         goto AFTER_MAIN_EXEC_ROW_LOOP;
11109         break;
11110     }

这里我们只关心Rows_log_event::do_hash_scan_and_update,主要做几件事

1.将当前行事件的记录前镜像和后镜像存储到一个hash中(Rows_log_event::do_hash_row);

hash表的结构定义在Hash_slave_rows类中

>>hash key的生成基于record[0],也就是前镜像;

>>前镜像记录的起始位置

>>前镜像记录的结束位置

对于hash scan,当有索引时(m_key_index<MAX_KEY),处理方式略微有些不一样:

在将记录加入到hash时,键值列被单独存储下来,存储在m_distinct_key_list中(Rows_log_event::add_key_to_distinct_keyset)

2.如果该EVENT中所有的行记录都解析完毕,开始执行SCAN && UPDATE (Rows_log_event::do_scan_and_update)

>>初始化表或者索引扫描(open_record_scan())

     对于索引,需要根据m_distinct_key_list初始化需要查询的键值iterator(m_itr)

>>在一个while循环中:

     |–>error= next_record_scan(i == 0);  //读取表或索引上的下一条记录

          |–>对于全表扫描,直接调用table->file->ha_rnd_next(table->record[0])扫描表记录

          |–>对于索引,第一次读是根据key搜索记录,下一次再调用next_record_scan时,先看下一条记录是否和当前m_key是否匹配,如果不匹配,将 m_key指向下一个m_itr,并根据m_key重读index,否则使用这个记录;

          这里看起来似乎有优化的余地,因为m_itr并不是有序的,它的成员取自m_distinct_key_list,并且也不会保证存储的Key完全不重复,从函数 add_key_to_distinct_keyset的逻辑可以看出来,每次加入一个新的key,仅仅和上一次的key做对比来判断是否重复,但实际上二级索引key在一个rows log event中可能是无序的,做一次排序 会不会有利于性能呢?(TODO)

     

     |–>根据读取到的记录构建key,查找hash,查看是否存在对应的entry(entry= m_hash.get(table, &m_cols))

     |–>如果存在entry,还需要把读取到的记录跟该entry对应的binlog中的行记录进行比较(防止hash collision),符合的话,则从hash中将其删除,并应用该更新(Rows_log_event::do_apply_row)

当发生错误,或者hash中记录删光后,结束扫描,从while退出

可见,对于没有索引的表而言,最多需要一次表扫描。


相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
SQL 缓存 关系型数据库
Mysql第十四天,Mysql并发参数调整
Mysql第十四天,Mysql并发参数调整
29 0
|
3月前
|
SQL 关系型数据库 MySQL
在云数据仓库AnalyticDB MySQL版中,有几个参数可能影响SELECT查询的执行及其稳定性
在云数据仓库AnalyticDB MySQL版中,有几个参数可能影响SELECT查询的执行及其稳定性【1月更文挑战第16天】【1月更文挑战第80篇】
290 4
|
3月前
|
存储 关系型数据库 MySQL
RDS有哪些参数?都有什么作用?
RDS有哪些参数?都有什么作用?
47 0
|
4月前
|
缓存 关系型数据库 MySQL
MySQL Binlog--事务日志和BINLOG落盘参数对磁盘IO的影响
MySQL Binlog--事务日志和BINLOG落盘参数对磁盘IO的影响
44 0
|
4月前
|
SQL 关系型数据库 MySQL
使用CTAS 把mysql 表同步数据 到hologres ,Flink有什么参数可以使hologres 的字段都小写吗?
使用CTAS 把mysql 表同步数据 到hologres ,Flink有什么参数可以使hologres 的字段都小写吗?
273 0
|
15天前
|
缓存 关系型数据库 MySQL
MySQL查询优化:提速查询效率的13大秘籍(合理使用索引合并、优化配置参数、使用分区优化性能、避免不必要的排序和group by操作)(下)
MySQL查询优化:提速查询效率的13大秘籍(合理使用索引合并、优化配置参数、使用分区优化性能、避免不必要的排序和group by操作)(下)
|
1月前
|
SQL 关系型数据库 MySQL
【Mysql】MYSQL参数max_allowed_packet 介绍
【Mysql】MYSQL参数max_allowed_packet 介绍
67 0
|
4月前
|
缓存 关系型数据库 MySQL
MySQL调优之服务器参数优化实践
MySQL调优之服务器参数优化实践
284 0
|
6月前
|
关系型数据库 MySQL Java
对比下 datax 的 OceanBase/MYSQL 不同数据同步方案的效率差异 || 聊聊参数 rewriteBatchedStatements
对比下 datax 的 OceanBase/MYSQL 不同数据同步方案的效率差异 || 聊聊参数 rewriteBatchedStatements
|
3月前
|
存储 SQL 缓存
MySQL `innodb_flush_log_at_trx_commit` 参数
MySQL `innodb_flush_log_at_trx_commit` 参数