March 2014

[MySQL5.6] MySQL 5.6.17新特性:online optimize table (以及其他主要bugfix)

在刚刚放出来的MySQL5.6.17版本中,最引人注意的功能当属于能够在线的进行opimitze table操作,这可以帮助减小表的大小而无需阻塞并发负载,另外以下几类操作也开始支持online ddl: OPTIMIZE TABLE ALTER TABLE … FORCE ALTER TABLE … ENGINE=INNODB (when run on an InnoDB table) 上述操作将触发表的rebuild,代码的改动量非常小 修改见 【Rev:5820】 这几个选项从sql_mode中移除了:ERROR_FOR_DIVISION_BY_ZERO, NO_ZERO_DATE, and NO_ZERO_IN_DATE;而是在严格模式中默认开启(【Rev:5829】) ALTER  IGNORE TABLE 也被弃用(目前只是打印warning,未来版本可能移除掉),根据描述,该类操作可能导致对unique key的ddl操作及外键操作以及复制问题  (搞不定一些问题就把他干掉。。。。呵呵)(修改见【Rev:5745】) 其他一些比较有意思的bugfix 【Rev:5800】 开始支持分区表的flush table for export,但依然不支持分区表的ALTER TABLE DISACARD/IMPORT TABLESPACE (不知道会否进一步开发) 【Rev:5846】 修复一个压缩表性能退化的bug(bug#71436) 调整了zip_mutex的顺序(buf_page_get_gen),当读入一个压缩页,实际上在递增计数器buf_pool->n_pend_unzip后,就可以直接释放buf_pool->zip_mutex 【Rev:5753】 purge协调线程和innodb monitor线程在shutdown时可能产生race condition(bug#70430) 因为purge线程退出时,还有可能进入到函数lock_print_info_summary中 , 之前的ut_error被移除掉了 另外一个和shutdown相关的bug, shutdown可能hang住(【Rev:5752】),也和purge线程的状态相关; 【Rev:5758】 在打开innodb_stats_persistent时,CREATE TABLE时需要向mysql.innodb_index_stats表中插入多条记录,每次插入都会commit一次,现在改成只commit一次(buf#70063) 见函数dict_stats_save_index_stat/dict_stats_save […]

[MySQL5.7] 5.7版本针对临时表的优化

尽量临时表在实际在线场景中很少会去显式使用,但在某些运维场景还是需要到的,在MySQL5.7中,专门针对临时表做了些优化;大概扫了下代码,把一些要点及关键函数记录下。 #独立的tmp表空间,默认在data目录下建立一个命名为ibtmp1的临时表表空间;对于非压缩临时表,表空间内容存放到ibtmp1下面;对于压缩表,依然会为其在tmp目录下建立ibd文件; #server启动时会删除之前的ibtmp文件并重建(函数srv_open_tmp_tablespace) #临时表空间使用全局变量srv_tmp_space(5.7里所有对表空间的管理的代码被重构成类Tablespace) #无需为临时表记录redo log,因为临时表不做crash recovery;因此在针对临时表的大量操作直接disable redo (dict_disable_redo_if_temporary) #临时表专用的回滚段,回滚段同样被记录到临时表空间ibtmp1下面(trx_sys_create_noredo_rsegs); 降低和其他实体表的undo log存储产生竞争 尽管临时表无需做crash recovery,但依然要为其创建undo log表空间,因为可能在事务执行的过程中,需要回滚到某个savepoint; 临时表的undo log无需写redo (实体表的undo是需要写redo的) 128个回滚段中的32个回滚段(srv_tmp_undo_logs)专门预留给临时表操作(回滚段trx_rsegs_t被分为两类:m_redo及m_noredo) 针对purge操作,也做了修改,采用一个优先队列来进行操作(具体见函数TrxUndoRsegsIterator::set_next(),  purge_sys->purge_queue, 在函数trx_purge_rseg_get_next_history_log中往队列加undo,创建临时表回滚段调用trx_sys_create_noredo_rsegs) 其他相关函数:trx_sysf_rseg_find_free,查找回滚段(get_next_redo_rseg及get_next_noredo_rseg, trx_assign_rseg_low) 对undo的修改详细见该patch: http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5832 #临时表的定义可以存放在内存,无需持久化到磁盘; 无需将临时表的元数据信息写入到系统表(对于临时表,create_table_def直接调用dict_build_tablespace && dict_table_add_to_cache 创建索引时同样区分对待(row_create_index_for_mysql) 其他相关函数:dict_build_index_def,dict_create_index_tree,dict_recreate_index_tree(include/dict0crea.h),这些函数用于对表元数据进行操作而无需更新系统表 #降低对临时表的锁约束,因为临时表只对当前client可见; 例如无需对更新临时表的二级索引页设置trx id, 不做可见性判断(lock_clust_rec_cons_read_sees, lock_sec_rec_cons_read_sees, lock_sec_rec_read_check_and_lock),不会去加innodb层表锁 (lock_table) 甚至对临时表而言记录锁也是多余的。 #避免对临时表使用change buffer.  另外在ibtmp表空间中的临时表也不为其分配Ibuf  bitmap page(fsp_fill_free_list) #增加了一个新的information schema表INNODB_TEMP_TABLE_INFO来显示临时表信息 root@test 12:41:54>create temporary table t1 (a int); Query OK, 0 rows […]

MySQL 5.7 增强的离线分析工具innochecksum

最近正准备写个工具来分析ibd文件中的数据分布,刚扫了下MySQL5.7的代码,发现这个功能已经在5.7.2版本中完成了;在新版本中增强了innochecksum的一些分析功能,完全可以满足我的需求 文档见:http://dev.mysql.com/doc/refman/5.7/en/innochecksum.html 相关代码见: http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/6065 http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5912 http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5841 http://bazaar.launchpad.net/~mysql/mysql-server/5.7/revision/5684 唯一的缺点就是:文件不可以打开!换句话说,可能需要关闭实例才能使用如下功能!!! 以下列出了几个感兴趣的命令,具体的可以参考文档!                                                                             . 输出ibd中总的page数: $sudo ./innochecksum –count ../data/sbtest/sbtest1.ibd Number of […]

[MySQL 5.6] Percona Server 5.6.16的主要改进

Percona刚刚放出了其最新的基于MySQL5.6.16的分支,在该版本中,Percona增加了几个比较有趣的特性,这里只列出我比较关心的,其他的自行参考官方Release Note (例如Percona对tokudb的支持应该是很多人关注的) Backup Locks 首先要提的是新特性 Backup Locks ,看起来是用来代替备份时臭名昭著的flush table with read lock 。主要增加了三个新的语法: LOCK TABLES FOR BACKUP //使用一种新的MDL锁来阻塞对非事务表的DML以及对所有表的DDL,但不阻塞SELECT查询 LOCK BINLOG FOR BACKUP //阻止对binlog位点的更新,也就是说对于DML/DDL操作会一直进行直到需要写入binlog的阶段被阻塞 UNLOCK BINLOG  // 解除LOCK BINLOG FOR BACKUP Percona的博客上专门写了篇博客来介绍关于备份加锁的历史发展以及对该特性的介绍,有兴趣的可以看看,另外也提到了Mariadb对备份的改进(将被include到下一个版本的Percona Server中) 另外Facebook很早就写了个补丁来绕过ftwrl,具体做法就是增加了新的语法,能够开启一个read view的同时返回当前与read view一致的binlog位点,但只适用于所有的表都是Innodb引擎; 具体的更改可以参考文档 及代码 LRU manager thread 使用新的独立后台线程来刷buffer pool的LRU链表,将这部分工作负担从page cleaner线程剥离。实际上就是直接转移刷LRU的代码到独立线程了, 实际从之前Percona的版本来看,都是在不断的强化后台线程,让用户线程少参与到刷脏/checkpoint这类耗时操作中 具体阅读Percona blueprint 及代码 page cleaner线程对server acitve的判断 在bug#71988中,描述了一种场景,即使每秒有activity,也会去做furous flush; Percona做的修改是,只有1秒钟内innodb没有任何active,才认为实例处于inactive状态,会去做100% IO Capacticy的刷脏操作(furious flush) 题外话:当前官方版本的Innodb,定义实例是否avtive的逻辑非常简单,做一个简单的DML,都会认为实例处于活跃状态,曾经观察到负载停止,而innodb 刷脏页的数据流量呈现出非常巨大的波动状态,结果发现是监控程序每秒做一次DML导致的(具体可以看我之前report的bug#69174) 修复5.6.16的一个性能退化bug […]

MySQL 5.6的优化器改进

本文整理了下MySQL5.6在优化器部分的相关知识点,不涉及任何代码内容,主要搜集了网上的一些相关资料(这是重点 :)) 子查询优化 首先要提的当然是臭名昭著的MySQL子查询问题,在MySQL5.5及之前的版本,所有有经验的MySQL DBA都会告诉你:绝不能在SQL的WHERE子句中使用子查询,因为那将可能产生灾难性的后果,因为很有可能每扫描一条数据,Where子查询都会被重新执行一遍,workaround的办法就是把WHERE里的子查询提升到FROM中,做成join操作; semi join的定义点wiki, MySQL需要满足如下条件,才会转换成Semi-join #子查询是IN或者=ANY的,不可以是NOT IN #子查询只能包含一个Query block,不可以有UNION等操作 #子查询不能包含GROUP BY或者HAVING #子查询不能包含聚合函数 #子查询谓语不可以是外接查询条件或者否定查询条件 #不可以包含STRAIGHT_JOIN限定词 #Semi-join只能用于SELECT或者INSERT,不可用于UPDATE和DELETE 偷个懒,上述总结翻译自这篇博文,官方文档上也有说明 和普通join查询不同的是,在semi join中,inner table 的结果集没有重复数据,当两表关联时,例如t1 semi join t2, 当t2存在匹配的记录时,返回t1的记录(t2的记录不会加入操作的结果集中),并且t1的记录最多只返回一次;不像inner join,每一个匹配的记录都会返回,对于semi join,在乎的只是是否匹配子查询而已。 当满足转换成semi join的条件时,就会将子查询进行转换,并选择如下策略之一去对记录进行去重: #TABLE PULLOUT, 直接使用TABLE PULLOUT,将子查询的表和outer表进行inner join;子查询上产生的记录本身需要具有唯一性,例如是primary key或者Unique key #Duplicate Weedout, 先和子查询做简单的inner join操作,并使用临时表(建有primary key)来消除重复记录; 在explain的extra字段会看到Start temporary和End temporary标识 下面几个图都偷的mariadb的博客上的,嘿嘿         mariadb的博客:duplicate  weedout #FirstMatch,当扫描inner table来组合数据时,并且有多个符合条件的数据时,只选择第一条满足条件的记录 […]