提到mysql压缩相关的内容,我们能想到的可能是如下几种和压缩相关的场景:

1、客户端和服务器之间传输的数据量太大,需要进行压缩,节约带宽

2、mysql某个列的数据量大,只针对某个列的数据压缩

3、mysql某个或者某几个表数据太多,需要将表数据压缩存放,减少磁盘空间的占用

这几个问题在mysql侧都有很好的解决方案 ,针对第1个问题,可以使用mysql的压缩协议解决;针对第2个问题,可以采用mysql的压缩和解压函数完美解决;而针对最复杂的第3个问题,则可以在引擎层面进行解决,目前myisam、innodb、tokudb、MyRocks等引擎都支持表的压缩。本篇文章要详细讨论的就是此类关于mysql压缩机制相关 的问题,下面是主要的内容:

一、mysql压缩协议介绍

1、适用场景

mysql压缩协议适合的场景是mysql的服务器端和客户端之间传输的数据量很大,或者可用带宽不高的情况,典型的场景有如下两个:

a、查询大量的数据,带宽不够(比如导出数据的时候)

b、复制的时候binlog量太大,启用slave_compressed_protocol参数进行日志压缩复制

2、压缩协议简介

压缩协议是mysql通信协议的一部分,要启用压缩协议进行数据传输,需要mysql服务器端和客户端都支持zlib算法。启动压缩协议会导致CPU负载略微上升。使用启用压缩协议使用-C参数或者 --compress=true参数启动客户端的压缩功能。如果启用了-C或者compress=true选项,那么在连接到服务器段的时候,会发送0x0020(CLIENT_COMPRESS)的服务器权能标志位,和服务器端协商通过后(3次握手以后),就支持压缩协议了。由于采用压缩,数据包的格式会发生变化,具体的变化如下:

未压缩的数据包格式:

 
 

压缩后的数据包格式:

 
 

大家可能留意到压缩后的数据报格式有压缩和未压缩之分,这个是mysql为了较少CPU开销而做的一个优化。如果内容小于50个字节的时候,就不对内容进行压缩,而大于50字节的时候,才会启用压缩功能。具体的规则如下:

当第三个字段的值等于0x00的时候,表示当前包没有压缩,因此n*byte的内容为1*byte,n*byte,即请求类型和请求内容。

当第三个字段的值大于0x00的时候,表示当前包已采用zlib压缩,因此使用的时候需要对n*byte进行解压,解压后内容为1*byte,n*byte,即请求类型和请求内容。

3、方案实践

在客户端连接的时候加上-C或者--compress=true参数。如果是对同步添加压缩协议支持的时候,则需要配置slave_compressed_protocol=1。下面是采用压缩协议连接mysql服务端的范例:

mysql -h hostip -uroot -p password --compress

mysqldump -h hostip -uroot -p password -default-character-set=utf8  --compress --single-transaction dbname tablename > tablename.sql

如果需要在主从复制中启用压缩传输,则在从机开启slave_compressed_protocol=1参数就OK。

4、压缩效果

可以通过在mysqldump中使用--compress选项来观察压缩传输的效果,也可以通过主从复制中已用slave_compressed_protocol参数来观察压缩传输的效果,很容易看出效果,这里不再截图说明。

二、mysql列压缩解决方案

mysql针对列的压缩目前直接的方案并不支持,映象中腾讯的Tmysql可以直接针对列的压缩。这里主要介绍一个曲线救国的办法,那就是在业务层面使用mysql提供的压缩和解压函数来针对列进行压缩和解压操作。也就是要对某一列做压缩,就需要在写入的时候调用COMPRESS函数对那个列的内容进行压缩,然后存放到对应的列。读取的时候,使用UNCOMPRESSED函数对压缩的内容进行解压缩。

1、适用场景

针对mysql中某个列或者某几个列数据量特别大,一般都是varchar、text、char等数据类型。

2、压缩函数简介

mysql的压缩函数COMPRESS压缩一个字符串,然后返回一个二进制串。使用该函数需要mysql服务端支持压缩,否则会返回NULL,压缩字段最好采用varbinary或者blob字段类型保存。使用UNCOMPRESSED函数对压缩过的数据进行解压。注意,采用这种方式需要在业务侧做少量改造。压缩后的内容存储方式如下:

a、空字符串就以空字符串存储

b、非空字符串存储方式为前4个bype保存未压缩的字符串,紧接着保存压缩的字符串

3、方案实践

字段压缩方案涉及到的几个相关的函数如下:

压缩函数

COMPRESS()

解压缩函数

UNCOMPRESS()

字符串长度函数

LENGTH()

未解压字符串长度函数

UNCOMPRESSED_LENGTH()

实践步骤:

a、创建一张测试表

CREATE TABLE  IF NOT EXISTS `test`.`test_compress` (

`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',

`content` blob NOT NULL COMMENT '内容列',

PRIMARY KEY (`id`)

) ENGINE=InnoDB  DEFAULT CHARSET=latin1 COMMENT='压缩测试表';

b、网表中插入压缩的数据

insert into `test`.`test_compress`(content) values(COMPRESS(REPEAT('a',1000)));

c、读取压缩的数据

select UNCOMPRESS(content) from `test`.`test_compress`;

d、查询对应的长度和内容

SELECT UNCOMPRESSED_LENGTH(content) AS length, LENGTH(content) AS compress_length, UNCOMPRESS(content), content FROM `test`.`test_compress`

4、压缩效果

 
 

从上面截图可以看出压缩效果比较好,针对text、char、varchr、blob等,如果里面重复的数据越多压缩效果就越好。

三、InnoDB表压缩方案解决方案

1、适用场景

采用压缩表一般都用在由于数据量太大,磁盘空间不足,负载主要体现在IO上,而服务器的CPU又有比较多的余量的场景。

2、表压缩简介

a、为什么需要压缩

目前很多表都支持压缩,比如Myisam、InnoDB、TokuDB、MyRocks 。由于使用InnoDB主要是不需要做什么改动,对线上完全透明,压缩方案也非常成熟,因此这里只对InnoDB做详细说明。对于TokuDB和MyRocks的压缩方案讲在mysql的压缩方案<二>中撰文说明。

在SSD没有大量横行的时候,数据库几乎都是IO负载型的,在CPU有大量余量的时候,磁盘IO的瓶颈就已经凸显出来。而数据的大量存储,尤其是日志型数据和监控类型的数据,会导致磁盘空间快速增长。硬盘不够用也会在很多业务中凸显出来。一种比较好的方式就诞生了,那就是通过牺牲少量CPU资源,采用压缩来减少磁盘空间占用,以及优化IO和带宽。尤其针对读多些少的业务。

SSD出来后,数据库的IO负载有所降低,但是对于磁盘空间的问题还是没有很好的解决。因此压缩表使用还是非常的广泛。这也就是为什么那么多的引擎都支持压缩的原因。而innodb在mysql 5.5的时候就支持了压缩功能,只是压缩比比较低,通常在50%左右。而tokuDB能达到80%左右,MyRocks的压缩比能达到70%左右。

注意:压缩比和你存储的数据组成有很大的关系,并不是所有的数据都能达到上面所说的压缩比。如果大部分都是字符串,并且重复的数据比较多,压缩比会很好。

b、innodb的压缩介绍

使用innodb压缩的前提条件是,innodb_file_per_table这个参数要启用,innodb_file_format这个参数设置成Barracuda。

你可以使用ROW_FORMAT=COMPRESSED来create或者alter表来开启innodb的压缩功能,如果没有指定KEY_BLOCK_SIZE的大小,默认KEY_BLOCK_SIZE为innodb_page_size大小的一半,也可以通过指定KEY_BLOCK_SIZE=n参数来开启innodb的压缩功能,n可以为1、2、4、8、16,单位是K。n的值越小,压缩比越高,消耗的CPU资源也越多。注意32K或者64K的页不支持压缩。启用压缩后,索引数据也同样会被压缩。

你也可以通过调整innodb_compression_level来设置压缩的级别,级别从1~9,默认是6。级别越低,意味着压缩比越高,同时也意味着需要更多的CPU资源。

c、压缩算法

innodb压缩借助的是著名的zlib库,采用L777压缩算法,这种算法在减少数据大小和CPU利用方面很成熟高效。同时这种算法是无损的,因此原生的未压缩的数据总是能够从压缩文件中重构,LZ777实现原理是查找重复数据的序列号然后进行压缩,所以数据模式决定了压缩效率,一般而言,用户的数据能够被压缩50%以上。

d、压缩表在buffer_pool中如何处理

在buffer_pool缓冲池中,压缩的数据通过KEY_BLOCK_SIZE的大小的页来保存,如果要提取压缩的数据或者要更新压缩数据对应的列,则会创建一个未压缩页来解压缩数据,然后在数据更新完成后,会将为压缩页的数据重新写入到压缩页中。内存不足的时候,mysql会讲对应的未压缩页踢出去。因此如果你启用了压缩功能,你的buffer_pool缓冲池中可能会存在压缩页和未压缩页,也可能只存在压缩页。不过可能仍然需要将你的buffer_pool缓冲池调大,以便能同时能保存压缩页和未压缩页。

mysql采用最少使用(LRU)算法来确定将哪些页保留在内存中,哪些页剔除出去,因此热数据会更多地保留在内存中。当压缩表被访问的时候,mysql使用自适应的LRU算法来维持内存中压缩页和非压缩页的平衡。当系统IO负载比较高的时候,这种算法倾向于讲未压缩的页剔除,一面腾出更多的空间来存放更多的压缩页。当系统CPU负载比较高的时候,mysql倾向于将压缩页和未压缩页都剔除出去,这个时候更多的内存用来保留热的数据,从而减少解压的操作。

e、如何评估KEY_BLOCK_SIZE是否合适

为了更深入地了解压缩表对性能的影响,在Information Schema库中有对应的表可以用来评估内存的使用和压缩率等指标。INNODB_CMP是收集的是某一类的KEY_BLOCK_SIZE压缩表的整体状况的信息,汇总的是所有KEY_BLOCK_SIZE压缩表的统计。而INNODB_CMP_PER_INDEX表则是收集各个表和索引的压缩情况信息,这些信息对于在某个时间评估某个表的压缩效率或者诊断性能问题很有帮助。INNODB_CMP_PER_INDEX表的收集会导致系统性能受到影响,必须innodb_cmp_per_index_enabled选项才会记录,生产环境最好不要开启。

我们可以通过观察INNODB_CMP表的压缩失败情况,如果失败比较多,则需要调大KEY_BLOCK_SIZE。一般建议KEY_BLOCK_SIZE设置为8。

3、方案实践

a、设置好innodb_file_per_table和innodb_file_format参数

SET GLOBAL innodb_file_per_table=1;SET GLOBAL innodb_file_format=Barracuda;

b、创建对应的压缩表

CREATE TABLE compress_test (c1 INT PRIMARY KEY,content varchar(255)) ROW_FORMAT=COMPRESSEDKEY_BLOCK_SIZE=8;

如果是已经存在的表,则通过alter来修改,SQL如下:

ALTER TABLEcompress_testROW_FORMAT=COMPRESSEDKEY_BLOCK_SIZE=8;

4、压缩效果

压缩效果通过线上的一个监控的表修改为压缩后的文件大小来说明,压缩前后对比如下:

 
 

四、参考文献

https://dev.mysql.com/doc/refman/5.7/en/innodb-compression-background.html

https://dev.mysql.com/doc/refman/5.7/en/general-tablespaces.html#general-tablespaces-creating

http://www.tocker.ca/2013/10/31/benchmarking-innodb-page-compression-performance.html

http://www.cnblogs.com/mysql-dba/p/5125220.html

http://hutaow.com/blog/2013/11/06/mysql-protocol-analysis/#11

https://my.oschina.net/tangcoffee/blog/362382

http://www.cnblogs.com/lispking/p/3604063.html

https://dev.mysql.com/doc/refman/5.7/en/innodb-table-compression.html

https://dev.mysql.com/doc/refman/5.7/en/innodb-compression-internals.html

作者:飞鸿无痕
链接:https://www.jianshu.com/p/d7cc90218222
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

Mysql压缩解决方案的更多相关文章

  1. MySQL 压缩解决方案

    From:https://www.qcloud.com/community/article/876100 导语 描述 MySQL 压缩的使用场景和解决方案,包括压缩传输协议.压缩列解决方案和压缩表解决 ...

  2. 远程无法连接Mysql 的解决方案

    问题描述: 新安装了MySQL 5.6,使用root用户无法远程连接, 提示Host 'xxx.xxx.xxx.xxx' is not allowed to connect to this MySQL ...

  3. 【已解决】Windows下 MySQL大小写敏感 解决方案及分析

    Windows下 MySQL大小写敏感配置 zoerywzhou@163.com http://www.cnblogs.com/swje/ 作者:Zhouwan 2017-3-27 最近在window ...

  4. MySql压缩版安装及避免1055错误和msvcp120.dll丢失

    MySql压缩版安装及避免1055错误和msvcp120.dll丢失 MySQL压缩版的安装快速方便,5.7及最新的8版本安装方式大致相同. 在使用group by分组时,可能会遇到1055错误. 另 ...

  5. MySQL序列解决方案

    MySQL序列解决方案 MySQLOracleSQL  MySQL自增长与Oracle序列的区别: 自增长只能用于表中的其中一个字段 自增长只能被分配给固定表的固定的某一字段,不能被多个表共用. 自增 ...

  6. MySQL 压缩文件安装遇到的问题及解决方案

    第一步:从官网下载压缩文件(链接). 第二步:解压该文件,放置到想放到的位置.我的目录是在 C:\mysql\mysql-8.0.12-winx64 下. 第三步:在C:\mysql\mysql-8. ...

  7. 试用阿里云RDS的MySQL压缩存储引擎TokuDB

    以前就用过自己搭建MySQL服务器的两种存储引擎MyISAM和InnoDB(也用过一点Memory方式),在今年初转向阿里云关系型数据库服务RDS的时候,看到可调参数中有一个TokuDB,不过不太了解 ...

  8. mysql error 1130 hy000:Host 'localhost' is not allowed to connect to this mysql server 解决方案

    ERROR 1130 (HY000): Host 'localhost' is not allowed to connect to this MySQL server D:\Wamp\mysql-\b ...

  9. MYSQL问题解决方案:Access denied for user 'root'@'localhost' (using password:YES)

    这两天在MyEclipse中开发Web项目时,连接MYSQL数据库,出现问题:Access denied for user 'root'@'localhost' (using password:YES ...

随机推荐

  1. ES6-Proxy and Reflect

    依赖文件地址 :https://github.com/chanceLe/ES6-Basic-Syntax/tree/master/js <!DOCTYPE html> <html&g ...

  2. Hadoop网站日志数据清洗——正则表达式实现

    周旭龙前辈的Hadoop学习笔记—网站日志分析项目案例简明.经典,业已成为高校大数据相关专业的实验项目.上周博主也完成了这个实验,不同于周前辈使用特殊符号切割字符串得到数据的做法,博主使用了正则表达式 ...

  3. node.js获取url中的各个参数

    实例代码test.js var http=require('http'); var url=require('url'); var querystring=require('querystring') ...

  4. HTML引入CSS样式的四种方法

    在HTML中引入CSS的方法主要有四种,它们分别是行内式.内嵌式.链接式和导入式. 1.行内式          行内式是在标记的style属性中设定CSS样式.这种方式没有体现出CSS的优势,不推荐 ...

  5. EF Core 实现多租户

    目录 SAAS 和多租户 多租户数据隔离方案 使用 EF Core 简单实现多租户 单数据库实现 多数据库实现 源代码 参考 SAAS 和多租户 SaaS(软件及服务)区别于其他应用程序的主要特征就是 ...

  6. antlr提取代码注释

    1. 来由 为什么要写提取注释呢,起因是工作需要.弄这么个不太重要的功能点来讲,旨在抛砖引玉. 一般而言,大家使用antlr解析源代码的时候,不会关心注释和空格之类内容,默认会过滤掉,不会放到语法树里 ...

  7. Walkway.js – 创建简约的 SVG 线条动画

    Walkway.js 是一个使用线条和路径元素组成 SVG 动画图像的简单方法.只需根据提供的配置对象创建一个新的 Walkway 实例就可以了.这种效果特别适合那些崇尚简约设计风格的网页.目前, W ...

  8. 用于深拷贝的扩展方法 C#

    using System.Runtime.Serialization.Formatters.Binary; using System.IO; public static class Tool { pu ...

  9. java类中成员的初始化顺序(一)

    类被创建之后的成员的初始化顺序到底是怎么样的? 首先 不考虑继承 package com; public class DemoOne { /** * 关于类的初始化顺序 */ //不考虑继承结构的情况 ...

  10. 解决:oracle+myBatis ResultMap 类型为 map 时返回结果中存在 timestamp 时使用 jackson 转 json 报错

    前言:最近在做一个通用查询单表的组件,所以 sql 的写法就是 select *,然后 resultType="map" ,然后使用 jackson @ResponseBody 返 ...