MySQL 5.7.5 版本,提供了Bulk Load方式创建索引,使用多路归并排序和批量写入的方法,是一种自下而上的方式。
步骤1: 扫描clustered index,写入sort buffer,等sort buffer写满了后,写入到临时文件中。 步骤2: 对临时文件中的有序记录进行归并排序。 步骤3: 批量写入到索引结构中。
批量写入: 因为记录都是有序的,所以写入的过程就是,不断的分配leaf page,然后批量写入记录,并保留innodb_fill_factor设置的空闲空间大小,所以,就是不断在最右边leaf page写入,并不断进行平衡B-Tree结构的过程。
从上面的步骤和几个维度的说明上,Bulk Load方式能显著的利用机器的吞吐量,加快创建index的过程。
问题及与Oracle的比较
1. 临时空间使用
MySQL使用临时目录来保存临时文件,对于文件的大小受限于目录空间大小,需要注意。RDS通过增加一个参数来控制临时空间的使用。Oracle使用临时表空间,如果排序空间不足,则会遇到常见的错误:ORA-01652: unable to extend temp segment by 128 in tablespace TEMP
2. redo保护
MySQL 的Bulk Load方式,没有使用redo保护,数据库从write-ahead logging方式退化成direct persist data,并且未来如果MySQL希望使用Innodb redo的方式进行复制,也变的困难。Oracle如果不指定no logging参数,索引创建过程中记录完整的redo信息。
3. direct write
MySQL Bulk Load方式,对于新的leaf page,在创建的过程中,唤醒page cleaner线程对这些page做checkpoint进行持久化。 Oracle提供一种用户的服务器进程直接direct write物理文件的方式,写入数据,而不依赖DBWR进程。MySQL· 捉虫动态·Opened tables block read only
背景
MySQL通过read_only参数来设置DB只读,这样MySQL实例就可以作为slave角色,只应用binlog,不接受用户修改数据。这样就可以保护master-slave结构中的数据一致性,防止双写风险。
global read_only的实现方式
MySQL5.5版本通过三个步骤来设置read_only:
步骤1:获取global read lock,阻塞所有的写入请求 步骤2:flush opened table cache,阻塞所有的显示读写锁 步骤3:获取commit lock,阻塞commit写入binlog 步骤4:设置read_only=1 步骤5:释放global read lock和commit lock。MySQL 5.5的版本,通过这5步完成设置read only的功能。
Bug描述
比如如下场景:
session1: lock table t read; session2: set global read_only=1;先执行session1,然后session2会一直被session1阻塞。
原因是:session1的显示锁,虽然与步骤1中的global read lock相容, 但session2因为session1一直持有读锁并保持t表opened而被阻塞。
但是,实际上,显示的读写锁产生的opened table并不影响read_only的功能,这里的flush tables也并非是必须的。
这也是我们的实际应用环境中,因主备切换而要在master实例上设置read_only的时候,经常被大查询所阻塞的原因。
修复方法
修复方法非常简单,只需要把步骤2删除即可,不影响read only的语义。
官方在MySQL 5.6.5中进行了修复:
If tables were locked by LOCK TABLES ... READ in another session, SET GLOBAL read_only = 1 failed to complete. (Bug #57612, Bug #11764747)
RDS功能增强