MySQL 5.6.12的Innodb性能改进

简单的记录下,在MySQL5.6.12中innodb层的3点跟性能相关的改进

1.在文件操作部分,移除了许多sleep操作,而是改用condition wait

对应的bug http://bugs.mysql.com/bug.php?id=68588。 在Mark的测试中,有近一倍的性能提升

http://bazaar.launchpad.net/~mysql/mysql-server/5.6/revision/4981

主要修改都几种在函数fil_flush中:

每个文件结构体node都增加了一个event:

fil_node_create:
     node->sync_event = os_event_create();
fil_node_free:
  os_event_free(node->sync_event)

fil_flush:

当文件上已经有线程在做flush时:

5638                 if (node->n_pending_flushes > 0) {
5639                         /* We want to avoid calling os_file_flush() on
5640                         the file twice at the same time, because we do
5641                         not know what bugs OS's may contain in file
5642                         i/o */
5643
5644                         ib_int64_t sig_count =
5645                                 os_event_reset(node->sync_event);
5646
5647                         mutex_exit(&fil_system->mutex);
5648
5649                         os_event_wait_low(node->sync_event, sig_count);
5650
5651                         mutex_enter(&fil_system->mutex);
5652
5653                         if (node->flush_counter >= old_mod_counter) {
5654
5655                                 goto skip_flush;
5656                         }
5657
5658                         goto retry;
5659                 }

5661                 ut_a(node->open);
5662                 file = node->handle;
5663                 node->n_pending_flushes++;
5664
5665                 mutex_exit(&fil_system->mutex);
5666
5667                 os_file_flush(file);
5668
5669                 mutex_enter(&fil_system->mutex);
5670
5671                 os_event_set(node->sync_event);
5672
5673                 node->n_pending_flushes--;

 

好吧,我承认我摘录上述代码的目的,只是简单记录下innodb condition wait的用法…

2.用户线程在查找空闲block,会刷单个page,这可能导致sync所有的文件

http://bazaar.launchpad.net/~mysql/mysql-server/5.6/revision/4955

http://bugs.mysql.com/bug.php?id=68658

用户线程做了single page flush后,加入一个IO异步请求队列后,会调用buf_flush_sync_datafiles.随后会唤醒IO线程,并在之后fsync所有的数据文件。          

该bzr主要修改包括:

* 所有batch flush操作异步进行(和以前一样)

buf_dblwr_flush_buffered_writes:

914         for (ulint i = 0; i < first_free; i++) {

915                 buf_dblwr_write_block_to_datafile(

916                         buf_dblwr->buf_block_arr[i], false);              // false表示异步写

917         }

* single page flush以寻找一个空闲块,这是同步操作

buf_flush_single_page_from_LRU->buf_flush_page->buf_flush_write_block_low->buf_dblwr_write_single_page

1130         /* We know that the write has been flushed to disk now

1131         and during recovery we will find it in the doublewrite buffer

1132         blocks. Next do the write to the intended position. */

1133         buf_dblwr_write_block_to_datafile(bpage, sync);      //该backtrace的sync为TRUE

buf_flush_page在多处被调用到,其增加了一个sync参数,用于表示该page flush操作需要同步还是异步进行。而在5.6.11中会在调用buf_flush_page后调用buf_flush_sync_datafiles()来sync所有的数据文件。

另外,有一种情况,在做SINGLE PAGE FLUSH时,采用异步的方式,backtrace如下:

row_import_for_mysql->buf_LRU_remove_pages->buf_flush_dirty_pages->buf_flush_or_remove_pages->buf_flush_page

这其实就是5.6的新特性ibd import功能的backtrace,后面单独开篇介绍

* 将single page flush的dblwr slot处理转移到IO线程

函数:buf_dblwr_update

当IO操作完成写一个page后,这个函数会被调用到,在5.6.12中会做两件事儿:

对于batch flush操作(BUF_FLUSH_LIST 或者BUF_FLUSH_LRU),当预留给batch flush的slot都全部完成刷新后(buf_dblwr->b_reserved = 0),会去sync数据文件(fil_flush_file_spaces(FIL_TABLESPACE)),将batch_running设为false,并发送完成信号

对于single page flush操作,找到当前page的slot,然后将其设置为未使用(in_use[i] = false),随后发送condition 信号(buf_dblwr->s_event)

这里采用顺序遍历,来寻找当前page的slot,是否存在效率问题?

而在5.6.11版本中,只考虑了batch flush操作。

* 移除对dblwr buffer中的sleep,改用condition wait

 写double write buffer时,如果已经在刷dblwr,以前是sleep 10ms,现在改成condition wait了,这里包括batch flush 和single page flush,这两者都增加了条件变量

当脏页刷新非常频繁时,会看到很明显的性能提升

*其他

另外一个没提到的修改是函数buf_flush_LRU_tail

在5.6.11的版本中,并没有对buf_flush_LRU的返回值进行处理。而在5.6.12中,增加了如下逻辑:

2092                 for (ulint j = 0;
2093                      j < scan_depth;
2094                      j += PAGE_CLEANER_LRU_BATCH_CHUNK_SIZE) {
2095
2096                         ulint   n_flushed = 0;
2097
2098                         /* Currently page_cleaner is the only thread
2099                         that can trigger an LRU flush. It is possible
2100                         that a batch triggered during last iteration is
2101                         still running, */
2102                         if (buf_flush_LRU(buf_pool,
2103                                           PAGE_CLEANER_LRU_BATCH_CHUNK_SIZE,
2104                                           &n_flushed)) {
2105
2106                                 /* Allowed only one batch per
2107                                 buffer pool instance. */
2108                                 buf_flush_wait_batch_end(
2109                                         buf_pool, BUF_FLUSH_LRU);
2110                         }
2111
2112                         if (n_flushed) {
2113                                 total_flushed += n_flushed;
2114                         } else {
2115                                 /* Nothing to flush */
2116                                 break;
2117                         }
2118                 }

3.优化batch flush的效率,之前的时间复杂度为O(N*N)

bug:http://bugs.mysql.com/bug.php?id=69170

http://bazaar.launchpad.net/~mysql/mysql-server/5.6/revision/4980

每个buffer pool实例增加了一个新的变量:

        const buf_page_t*       flush_list_hp;/*!< “hazard pointer”

used during scan of flush_list

while doing flush list batch.

Protected by flush_list_mutex */

根据注释,其在批量刷新时使用,用flush_list_mutex 来保护

buf_flush_set_hp :设置flush_list_hp指针,指向参数传递的page

buf_flush_update_hp:当flush_list上的block移除或者移动时,需要检查buf_flush_set_hp指针是否被其他正在扫描flush list的线程设置,如果flush_list_hp指向我们下一个将要扫描的page,则将其设置为NULL,表示需要重新扫描

有两个地方会调用到这个函数:

* 从flush list上移除一个page的时候(buf_flush_remove)

* 为flush list上的一个page重分配控制块,buf_flush_relocate_on_flush_list

buf_do_flush_list_batch:

在该函数的修改是核心部分,主要消除了在bug#69170中描述的o(n*n)的时间复杂度。所有作用于flush list的线程,都需要先检查flush_list_hp指针,

这里的方法很简单,从flush list的尾部开始扫描, 每次获取一个page后,将bp->flush_list_hp的指针指向该page的前一个, 然后释放bp->flush_list_mutex

然后执行该page的刷新

flushed = buf_flush_page_and_try_neighbors(

bpage, BUF_FLUSH_LIST, min_n, &count);

再次持有flush_list_mutex锁,查看bp->flush_list_hp是否发生变化,如果发生变化了,则表明该指针被其他线程设置了,也就是说,有其他线程对flush list做了操作,因此需要从flush list尾部重新开始扫描

在5.6.11的版本中,总是无条件的从尾部开始重新扫描。

 

时间: 2024-08-31 07:21:26

MySQL 5.6.12的Innodb性能改进的相关文章

MySQL内核月报 2015.01-MySQL · 优化改进· 复制性能改进过程

前言 与oracle 不同,mysql 的主库与备库的同步是通过 binlog 实现的,而redo日志只做为mysql 实例的crash recovery使用.mysql在4.x 的时候放弃redo 的同步策略而引入 binlog的同步,一个重要原因是为了兼容其它非事务存储引擎,否则主备同步是没有办法进行的. redo 日志同步属于物理同步方法,简单直接,将修改的物理部分传送到备库执行,主备共用一致的 LSN,只要保证 LSN 相同即可,同一时刻,只能主库或备库一方接受写请求: binlog的同

MySql删除和更新操作对性能有影响吗_MsSql

删除和更新操作的开销往往比插入高,所以一个好的设计需要减少对数据库的更新和删除操作. 3.1更新操作 数据库的更新操作会带来一连串的"效应":更新操作需要记录日志(以便错误时回滚):更新可变长字段(如,varchar类型)会带来数据物理存储的变化(记录的移动):更新索引字段会导致索引重建:更新主键会导致数据重组等.这一切不但会造成更新操作本身效率低,而且由于磁片碎片的产生会造成以后查询性能的降低.为了应对这一情况,有两种策略:一.减少更新次数,把多个字段的更新写到同一个语句里:二.避免

MySql删除和更新操作对性能有影响吗

删除和更新操作的开销往往比插入高,所以一个好的设计需要减少对数据库的更新和删除操作. 3.1更新操作 数据库的更新操作会带来一连串的"效应":更新操作需要记录日志(以便错误时回滚):更新可变长字段(如,varchar类型)会带来数据物理存储的变化(记录的移动):更新索引字段会导致索引重建:更新主键会导致数据重组等.这一切不但会造成更新操作本身效率低,而且由于磁片碎片的产生会造成以后查询性能的降低.为了应对这一情况,有两种策略:一.减少更新次数,把多个字段的更新写到同一个语句里:二.避免

mysql数据据存储引擎InnoDB和MyISAM的优势及区别

MyISAM:这个是默认类型,它是基于传统的ISAM类型,ISAM是Indexed Sequential Access Method (有索引的顺序访问方法) 的缩写,它是存储记录和文件的标准方法.与其他存储引擎比较,MyISAM具有检查和修复表格的大多数工具. MyISAM表格可以被压缩,而且它们支持全文搜索.它们不是事务安全的,而且也不支持外键.如果事物回滚将造成不完全回滚,不具有原子性.如果执行大量的SELECT,MyISAM是更好的选择. InnoDB:这种类型是事务安全的.它与BDB类

MySQL正确的myisam转innodb的方法

这里简单的介绍一下两者间的区别和转换方法: MyISAM:MyISAM是MySQL5.5之前版本默认的数据库存储引擎.MYISAM提供高速存储和检索,以及全文搜索能力,适合数据仓库等查询频繁的应用.但不支持事务.也不支持外键.MyISAM格式的一个重要缺陷就是不能在表损坏后恢复数据. InnoDB:InnoDB是MySQL5.5版本的默认数据库存储引擎,不过InnoDB已被Oracle收购,MySQL自行开发的新存储引擎Falcon将在MySQL6.0版本引进.InnoDB具有提交.回滚和崩溃恢

mysql 5.7以上版本安装配置方法图文教程(mysql 5.7.12\mysql 5.7.13\mysql 5.7.14)_Mysql

之前安装mysql 5.7.12时未做总结,换新电脑,补上安装记录,安装的时候,找了些网友的安装记录,发现好多坑 (一)mysql 5.7.13 安装配置方法 1.mysql-5.7.12-winx64.zip下载官方下载地址:http://dev.mysql.com/downloads/mysql/ 2.解压到C:\job\mysql-5.7.12-winx64 3.在C:\job\mysql-5.7.12-winx64下新建my.ini配置文件内容如下: ##################

MySQL · 源码分析 · 词法分析及其性能优化

Table of Contents 1. 简介 2. 背景知识 3. 查找树的实现 3.1. 树的查找 3.2. 树的产生 4. 试试折半查找 5. 总结 简介 MySQL 支持标准的 SQL 语言,具体实现的时候必然要涉及到词法分析和语法分析.早期的程序可能会优先考虑手工实现词法分析和语法分析,现在大多数场合下都会采用工具来简化实现.MySQL.PostgreSQL 等采用 C/C++ 实现的开源数据库采用的是现代的 yacc/lex 组合,也就是 GNU bison/flex.其他比较流行的

深入解析MySQL的事务隔离及其对性能产生的影响_Mysql

 SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的.低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销.Read Uncommitted(读取未提交内容)       在该隔离级别,所有事务都可以看到其他未提交事务的执行结果.本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少.读取未提交的数据,也被称之为脏读(Dirty Read).Read Committed(读取提交内容)       这是大多数数据库系统的默认隔离级别(

CentOS 6.5 下MySQL 5.7.12主从复制配置详解

为什么使用主从架构? 1.实现服务器负载均衡: 2.通过复制实现数据的异地备份: 3.提高数据库系统的可用性: 4.可以分库[垂直拆分],分表[水平拆分]: 主从配置的前提条件 1.MySQL版本一致: 你还没有安装MySQL? 请参考:CentOS 6.5 下安装MySQL 5.7.12,使用官网下载的rpm安装包 2.MySQL中的数据一致: 不一致就把它们搞一致! 3.操作前停止一切更新操作(写入.更新.删除等): 配置master(主服务器) vi /etc/my.cnf #[必须]启用