大家在使用MySQL数据库的时候经常会发现新建的数据库及表用起来非常的流畅,但是当数据库使用一段时间后,随着数据量的增大再进行数据操作时经常会出现卡顿的现象,哪怕你的表中只有几十条数据也会出现查询时间过长的问题。
下图就是对一张表的查询,大家可以看出表中数据一共16行可是查询时间却用了45s多,你可能会说你的查询语句有问题,不要使用select *
,可是即使你使用了select id,name...
来优化sql速度并不会提升。
眼尖的同学可能会发现,咦,你的id那一列怎么那么大呢?都到了3千多万。好吧,我承认为了引出今天的问题我是做了点手脚了。接下来就引出今天要给大家分享的Mysql数据空洞的问题。
MySQL的数据存储在表空间中,有的时候我们删除了一张表的一半的数据,但是发现表空间文件的大小并没有减少,这是什么原因呢?
当对一条数据执行delete操作时,MySQL将数据删除后,并未将数据占用的空间返还给操作系统,而是将当前空间标记为"可复用",当有新的数据插入时,则不会重新申请空间,而是插入到"可复用"空间中,这种"可复用"空间,称之为数据空洞。
MySQL官方文档对此的解释如下:
After deleting a large part of a MyISAM or ARCHIVE table, or making many changes to a MyISAM or ARCHIVE table with variable-length rows (tables that have VARCHAR, VARBINARY, BLOB, or TEXT columns).
Deleted rows are maintained in a linked list and subsequent INSERT operations reuse old row positions.
数据空洞的好处是尽可能的复用表空间结构,带来的问题也是显而易见,当删除数据后,表空间并未及时的释放,当长时间没有新的数据填充,会造成空间浪费的情况。
为了深入的研究数据空洞的问题建议大家亲手实践一遍,只有亲自经历过记忆才能深刻,当你再次遇到类似的问题时会立刻想起相应的解决方案来。
1.新建一个测试表
create table emp(
id int(11) primary key auto_increment,
name varchar(20) not null,
deptId int(11),
salary float
);
2.插入一些测试数据
insert into emp(name,deptId,salary) values("Alice",1001,20394),("Carry",1002,20394),("scott",1001,3943),("Tiger",1003,10394),("Kalin",1003,30493),("Marry",1004,20394),("Tom",1003,10934),("Mike",1003,4039);
3.构造一批数据
insert into emp(name,deptId,salary) select name,deptId,salary from emp;
可以通过反复执行上面的sql语句来构建一批数据,当然你可以使用存储过程来实现,这里我使用了反复执行上面语句的方式来构建了3千多万条记录。
通过上图大家可以看出大量数据写库时时间的增长。
直到你表中的记录数达到3千多万后再清除一下表。
delete from emp;
然后再重新添加一些数据。
insert into emp(name,deptId,salary) values("Alice",1001,20394),("Carry",1002,20394),("scott",1001,3943),("Tiger",1003,10394),("Kalin",1003,30493),("Marry",1004,20394),("Tom",1003,10934),("Mike",1003,4039);
查看一下表的存储空间,虽然只有十几条数据,可是存储空间却达到了700多M,这700多M就是数据空洞产生的了,这也是我们表中虽然只有十几条数据可是查询却花了40多秒的原因了。
使用optimize
命令可以解决数据空洞问题。
optimize table emp;
下图是执行完optimize
命令后的截图。
再次查看表存储空间,你会发现大大的缩小了。
再次查询数据,速度得到了极大的提升,下图为证。
Mysql是大家目前最常用的数据库,有时我们会频繁的插入删除数据,在频繁的进行表操作后可能会出现数据空洞的问题,判断的标准就是你表中实际存储的数据条数和存储空间产生了极大的差距,此时你就要考虑数据空洞的问题了,可以使用optimize
命令对表进行优化。
但是optimize
命令会锁表,所以大家也不要频繁的去使用这条命令,通过自己的判断数据表中的确出现了数据空洞时再执行,以防出现频繁锁表的新问题。