关于InnoDB表的page利用率和optimize table

上一篇我们介绍了ibd_used这个工具,我们用来量化看表数据文件的page使用率。这里用来说明optimize table这个命令的问题和优化。

实例准备

建一个这样的表


CREATE TABLE `tb` (

`seq_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,

`a` varchar(32) DEFAULT NULL,

`b` varchar(32) DEFAULT NULL,

`c` varchar(32) DEFAULT NULL,

`d` char(255) DEFAULT NULL,

Primary key (seq_id),
KEY a (a),

KEY bc (b,c),

KEY cb (c,b)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

执行语句为“insert into tb(a,b,c) values(randstr, randstr, randstr);” randstr是客户端程序生成的长度30字节的随机字符串。30个线程并发,每个线程插入1w条记录。

等待更新完成后(包括purge完成,从系统的vmstat上看无任何io),执行./ibd_used tb.ibd 0 100000000,可以从最后4行看到各个索引的page平均利用率如下图。

说明: 你会发现即使是主键索引,利用率也不一定很高。原因是什么?

Optimize table 效果

我们知道Optimize table是用来作表整理的, 执行一下 optimize table tb,再看ibd_used的结果。

说明:这里我们发现,pk的page利用率明显提升,是optimize效果,但是其他几个索引的page利用率却没有明显效果。为什么呢?

1) 首先是上面没有提的那个“异常”,既然是自增主键,为什么在optimize之前,pk的利用率不高?原因是多线程插入,虽然seq_id是递增申请,但不能保证是递增更新到page上。而通过optimize后,等于是单线程重新整理了。

2) 为什么其他索引的page利用率没有提升,这个就涉及到optimize table的内部执行过程。如下:

a) 建一个临时表,表结构与tb相同

b) 按照tb主键顺序将tb数据一行行的插入到临时表中

c) 删掉tb,临时表重命名为tb

所以我们看到对于其他索引,插入的值仍然是随机的过程。

改进的思路

我们知道InnoDB在5.1的时候innodb_plugin里面就有fast index creatation了,上述过程如果改成如下:

a) 建一个临时表,表结构与tb相同

b) 删掉临时表的所有非聚簇索引

c) 按照tb主键顺序将tb数据一行行的插入到临时表中

d) 建立临时表的所有非聚簇索引

e) 删掉tb,临时表重命名为tb

这样在执行步骤d)时,每个非聚簇索引都是按照排序好方式构建,则能让所有的索引page都很“紧凑”。

Percona版本的 expand_fast_index_creation参数

在Percona版本中新增了这个参数,默认值是OFF,需要配置文件设置ON或者通过set命令热修改。

当设置为ON时,则optimize table tb实现的就是上述我们说到的改进流程。从ibd_used看到执行结果看到的效果如下:

小结

所以当你需要通过optimze table优化表空间,

若是使用percona版本则最好先打开expand_fast_index_creation;

若是官方版本,则建议自己写脚本建临时表,按照上述的过程a~e来执行,达到最优的效果。

时间: 2024-09-12 21:58:57

关于InnoDB表的page利用率和optimize table的相关文章

MySQL数据库INNODB 表损坏修复过程

  突然收到MySQL报警,从库的数据库挂了,一直在不停的重启,打开错误日志,发现有张表坏了.innodb表损坏不能通过repair table 等修复myisam的命令操作.现在记录下解决过程,下次遇到就不会这么手忙脚乱了. 处理过程: 一遇到报警之后,直接打开错误日志,里面的信息: InnoDB: Database page corruption on disk or a failed InnoDB: file read of page 30506. InnoDB: You may have

查看InnoDB的磁盘空间利用率

这周阿里集团DBA内部分享时,支付宝的黄忠同学提了一个问题,关于InnoDB索引page 的利用率. page利用率 主要是指btee里面每个page的使用被使用的空间大小.我们知道InnoDB默认一个page大小是16k.但实际使用情况不会总用满 我们定义为所有page的总使用字节除以总字节数. 在理论分析之前,我们要先弄个工具,查一下. 实例统计 写了一个简单的工具,读ibd文件上的每个page,算出每个page的实际使用字节,可以得到利用率. 我们找了线上一个库来模拟.表中有1个自增主键和

MySQL数据库INNODB表损坏修复处理过程分享_Mysql

突然收到MySQL报警,从库的数据库挂了,一直在不停的重启,打开错误日志,发现有张表坏了.innodb表损坏不能通过repair table 等修复myisam的命令操作.现在记录下解决过程,下次遇到就不会这么手忙脚乱了. 处理过程: 一遇到报警之后,直接打开错误日志,里面的信息: InnoDB: Database page corruption on disk or a failed InnoDB: file read of page 30506. InnoDB: You may have t

MySQL InnoDB表空间及日志文件简介

MySQL一个显著的特点是其可插拔的存储引擎,因此MySQL文件分为两种:一种是MySQL服务器本身的文件(主要是一 些日志文件,如错误日志.二进制日志等),所有的存储引擎共享:另一种是和具体存储引擎相关的文件.本文主要介 绍和InnoDB存储引擎相关的文件(数据+日志),至于MySQL服务器本身的日志文件,可以参考<[MySQL] 日志文件概述 >. InnoDB表空间文件 InnoDB在很多方面和Oracle非常像,它的数据也是按表空间存储的,表空间是一个在逻辑上为整体的存储块,默认情 况

数据库内核月报 - 2015 / 08-MySQL · 社区动态 · MariaDB InnoDB表空间碎片整理

介绍 当你对InnoDB进行修改操作时,例如删除一些行,这些行只是被标记为"已删除",而不是真的从索引中物理删除了,因而空间也没有真的被释放回收.InnoDB的Purge线程会异步的来清理这些没用的索引键和行,但是依然没有把这些释放出来的空间还给操作系统重新使用,因而会导致页面中存在很多空洞.如果表结构中包含动态长度字段,那么这些空洞甚至可能不能被InnoDB重新用来存新的行,因为空间空间长度不足. 有些用户可能会使用 OPTIMIZE TABLE 或者 ALTER TABLE <

提高MySQL中InnoDB表BLOB列的存储效率的教程_Mysql

首先,介绍下关于InnoDB引擎存储格式的几个要点: 1.InnoDB可以选择使用共享表空间或者是独立表空间方式,建议使用独立表空间,便于管理.维护.启用 innodb_file_per_table 选项,5.5以后可以在线动态修改生效,并且执行 ALTER TABLE xx ENGINE = InnoDB 将现有表转成独立表空间,早于5.5的版本,修改完这个选项后,需要重启才能生效: 2.InnoDB的data page默认16KB,5.6版本以后,新增选项 innodb_page_size

MySQL 5.7.6: wl#5757 InnoDB支持大page

worklog: http://dev.mysql.com/worklog/task/?id=5757 官方mysql 在git上代码比较零散,具体的实现我们可以参考webscalesql上的代码:https://reviews.facebook.net/D31107 或者在webscalesql的git上: git show ebd27a35db6ef2267efd69da392e5efdc77611a6 我们知道Innodb的默认page size为16KB.在MySQL5.6版本里我们可以

REPAIR TABLE和OPTIMIZE TABLE优化表和修复表

REPAIR TABLE `table_name` 修复表OPTIMIZE TABLE `table_name` 优化表 REPAIR TABLE 用于修复被破坏的表.OPTIMIZE TABLE 用于回收闲置的数据库空间,当表上的数据行被删除时,所占据的磁盘空间并没有立即被回收,使用了OPTIMIZE TABLE命令后这些空间将被回收,并且对磁盘上的数据行进行重排(注意:是磁盘上,而非数据库).多数时间并不需要运行OPTIMIZE TABLE,只需在批量删除数据行之后,或定期(每周一次或每月一

InnoDB 中文参考手册 --- 4 建立 InnoDB 表

参考|参考手册|中文 4 建立 InnoDB 表假设你已以 mysql test 命令方式运行了 MySQL 客户端程序.为了建立一个 InnoDB 格式的表你必须在 SQL 命令中指定 TYPE = InnoDB : CREATE TABLE CUSTOMER (A INT, B CHAR (20), INDEX (A)) TYPE = InnoDB; 这个 SQL 命令将在 my.cnf 中设定的 InnoDB 数据文件中创建一个表和一个列 A 的索引,同时将在 MySQL 数据目录下的 t