压缩算法:innodb plugin采用了 zlib library函式库的LZ77 的压缩算法来对数据进行压缩,这种算法已经很成熟,在cpu利用率,压缩比率在50%以上,更为重要的是无数据丢失;
innodb的数据存储方式:innodb在数据储存上采用聚簇的方式(B-树)来组织数据,叶子节点上存放了表中定义的所有列数据;第二索引同样也是B-树结构,在索引列的后面会加上聚簇键列,用于索引列到聚簇索引查找数据;
压缩B-树:由于对B-树的频繁的更新,进而导致B-树的页节点的分裂,不断的对数据进行解压,压缩,innodb面对这种情况,对其进行了优化:在B-树压缩页维护一些系统信息,来表明已经被更新,如对于删除来说,innodb采用打is_deleted的标记,不需要任何的压缩解压操作;当索引页的值发生变化的时候,为了避免不必要的解压和压缩,innodb在压缩页上维护了一个modification log用于记录页的所有改变,insert,update的值会记录到modification log中,而不用重构整个页,当该页modification log的空间不够时,innodb才会解压该页,然后应用log,再对该页重新压缩;当重压缩失败时,叶节点就会分裂,直到insert,update成功;
innodb在innodb buffer pool中怎样处理压缩页:
在一个采用了压缩特性的表中,每一个压缩页(1k,2k,4k,8k,16k)都对应了一个16k的非压缩页,当需要读取压缩页中的数据的时候,如果压缩页不在buffer中,则从磁盘上读到buffer中,然后在对该压缩页进行解压到16k的页;
为了减少i/o以及对页的解压,在buffer中同时存在压缩和未压缩的页;为了给其他需要空间的腾出空间,innodb会将未压缩的页写到磁盘上,保留压缩页在buffer中,也有可能需要将一些没有被访问的压缩页写到磁盘上,因此buffer pool中可能有压缩和未压缩的页,或者只有压缩页;buffer pool采用LRU算法来保证热点页尽量的存放在buffer中,同时为了该LRU算法会评估当前系统正在处于一种什么样的状态,是i/o瓶颈还是cpu瓶颈:当系统正处于i/o瓶颈的时候,innodb倾向于将未压缩页写到磁盘上,以此来腾出更多的空间用于其他的页存放到buffer;当系统正处于cpu瓶颈的时候,inondb倾向于将未压缩和压缩页都写到磁盘上,以此来让更多内存存放热点页,同时减少未压缩页的比例,让更多的压缩页在内存中;
在将压缩页写到数据文件前,innodb会将该页写到redo log中,因此这样就导致了log file会变得很大,同时在进行压缩的时候,需要做一次检查点(log file的大小已经检查点的频率取决于压缩页重组已经重新压缩的次数)。
压测:采用sysbench压测了一下compress的性能,2.5kw数据,未压缩大小为5.7G,采用key_block_size=8压缩后为2.9G:
1GB(BP) 2GB(BP) 4GB(BP) 8GB(BP) 16GB(BP)
compress(2.9G) 487.17 424.85 657.35 694.5 664.32
nocompress(5.7G) 284.12 727.73 933.43 1024.17 1108.8
./sysbench –test=oltp –mysql-table-engine=innodb –num-threads=5 –oltp-table-size=25000000 –mysql-user=root –mysql-socket=/u01/mysql/run/mysql.sock run&
CREATE TABLE `sbtest` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`k` int(10) unsigned NOT NULL DEFAULT ‘0’,
`c` char(120) NOT NULL DEFAULT ”,
`pad` char(60) NOT NULL DEFAULT ”,
PRIMARY KEY (`id`), KEY `k` (`k`)) ENGINE=InnoDB DEFAULT CHARSET=gbk ROW_FORMAT = COMPRESSED key_block_size=8k;
ref:innodb plugin 官方手册innodb plugin 特性innodb compression woesinodb compression:when more is lesss