前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >MySQL表压缩和页压缩,难道只是空间压缩?

MySQL表压缩和页压缩,难道只是空间压缩?

作者头像
SEian.G
发布于 2022-01-18 02:42:58
发布于 2022-01-18 02:42:58
3.3K00
代码可运行
举报
文章被收录于专栏:SEian.G学习记录SEian.G学习记录
运行总次数:0
代码可运行

临近春节,相信每个公司都会进行全面巡检,无论是业务层还是数据库层,达到事前预防的目的;今天就来分享一下针对MySQL数据存储层面,在数据库存储来不及扩容的情况下,MySQL中的压缩方案;

日常工作中很多业务在表结构设计之初不会考虑存储的设计,只有当业务发展到一定规模才会意识到问题的严重性。而物理存储主要是考虑是否要启用表的压缩功能,默认情况下,所有表都是非压缩的。但说到压缩,总会下意识地认为压缩会导致 MySQL 数据库的性能下降。这个观点说对也不对,需要根据不同场景进行区分。

目前很多引擎表支持压缩,比如 Myisam、InnoDB、TokuDB、MyRocks 。本文主要是针对Innodb引擎表压缩进行说明,针对MyRocks引擎的详细可参考:《RocksDB引擎和Innodb性能对比》

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

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

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

表压缩

数据库中的表是由一行行记录(rows)所组成,每行记录被存储在一个页中,在 MySQL 中,一个页的大小默认为 16K,一个个页又组成了每张表的表空间。通常我们认为,如果一个页中存放的记录数越多,数据库的性能越高。这是因为数据库表空间中的页是存放在磁盘上,MySQL 数据库先要将磁盘中的页读取到内存缓冲池,然后以页为单位来读取和管理记录。

一个页中存放的记录越多,内存中能存放的记录数也就越多,那么存取效率也就越高。若想将一个页中存放的记录数变多,可以启用压缩功能。此外,启用压缩后,存储空间占用也变小了,同样单位的存储能存放的数据也变多了。

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

COMPRESS 页压缩是 MySQL 5.7 版本之前提供的页压缩功能。只要在创建表时指定ROW_FORMAT=COMPRESS,并设置通过选项 KEY_BLOCK_SIZE 设置压缩的比例;如果没有指定 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 资源。

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

如下是官方文档描述:

In the buffer pool, the compressed data is held in small pages, with a page size based on the KEY_BLOCK_SIZE value. For extracting or updating the column values, MySQL also creates an uncompressed page in the buffer pool with the uncompressed data. Within the buffer pool, any updates to the uncompressed page are also re-written back to the equivalent compressed page. You might need to size your buffer pool to accommodate the additional data of both compressed and uncompressed pages, although the uncompressed pages are evicted from the buffer pool when space is needed, and then uncompressed again on the next access.

总之,COMPRESS 页压缩,适合用于一些对性能不敏感的业务表,例如日志表等

为了 解决压缩性能下降的问题,从MySQL 5.7 版本开始推出了 TPC 压缩功能,其利用文件系统的空洞(Punch Hole)特性进行压缩。

TPC 压缩( Innodb Transaparent PageIO Compression)

可以使用下面的命令创建 TPC 压缩表:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
CREATE TABLE Transaction (
id BINARY(16) PRIMARY KEY,
.....
)
COMPRESSION=ZLIB | LZ4 | NONE;

要使用 TPC 压缩,首先要确认当前的操作系统是否支持空洞特性。通常来说,当前常见的 操作系统都已支持空洞特性:

Linux系统上,文件系统块大小是空洞特性的单位大小。因此,只有当页面数据可以压缩到小于或等于InnoDB页面大小减去文件系统块大小时,页面压缩才起作用。例如,如果innodb_page_size=16K,文件系统块大小为4K,则页面数据必须压缩到小于或等于12K,才能生效。

这是因为不同于 COMPRESS 页压缩,TPC 压缩在内存中只有一个 16K 的解压缩后的页,对于缓冲池没有额外的存储开销。

表压缩在业务上的使用

总的来说,对一些对性能不敏感的业务表,例如日志表、账单表等,它们只对存储空间有要求,因此可以使用 COMPRESS 页压缩功能。

在一些较为核心的流水业务表上,更推荐使用 TPC压缩。因为流水信息是一种非常核心的数据存储业务,通常伴随核心业务。如一笔交易,下单、记流水,这就是一个核心业务的模型。

所以,用户对流水表有性能需求。此外,流水又非常大,启用压缩功能可更为有效地存储数据。

若对压缩产生的性能抖动有所担心,我的建议:由于流水表通常是按月或天进行存储,对当前正在使用的流水表不要启用 TPC 功能,对已经成为历史的周期表启用 TPC 压缩功能,如下所示:

需要特别注意的是:通过命令 ALTER TABLE xxx COMPRESSION = ZLIB 可以启用 TPC 页压缩功能,但是这只对后续新增的数据会进行压缩,对于原有的数据则不进行压缩。所以上述ALTER TABLE 操作只是修改元数据,瞬间就能完成。

若想要对整个表进行压缩,需要执行 OPTIMIZE TABLE 命令:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ALTER TABLE dic_history_202201 COMPRESSION=ZLIBOPTIMIZE TABLE dic_history_202201;

禁用页面压缩

使用ALTER TABLE将compression设置为None。设置COMPRESSION=None后发生的表空间写入不再使用页压缩。要解压缩现有页面,必须在设置COMPRESSION=None后使用OPTIMIZE table重新生成表。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ALTER TABLE dic_history_202201 COMPRESSION="None";
OPTIMIZE TABLE dic_history_202201;

页压缩元数据

页压缩元数据存储在 INFORMATION_SCHEMA.INNODB_TABLESPACES表中,表中有三列:

FS_BLOCK_SIZE: The file system block size, which is the unit size used for hole punching. #文件系统块大小 FILE_SIZE: The apparent size of the file, which represents the maximum size of the file, uncompressed. #文件的实际大小,表示未压缩文件的最大大小 ALLOCATED_SIZE: The actual size of the file, which is the amount of space allocated on disk. # 文件的实际大小,即磁盘上分配的空间量

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql>show create table employees\G
*************************** 1. row ***************************
Table: employees
Create Table: CREATE TABLE `employees` (
`emp_no` int NOT NULL,
`birth_date` date NOT NULL,
`first_name` varchar(14) NOT NULL,
`last_name` varchar(16) NOT NULL,
`gender` enum('M','F') NOT NULL,
`hire_date` date NOT NULL,
PRIMARY KEY (`emp_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMPRESSION='zlib'
1 row in set (0.00 sec)
 
mysql>SELECT SPACE, NAME, FS_BLOCK_SIZE, FILE_SIZE, ALLOCATED_SIZE FROM INFORMATION_SCHEMA.INNODB_TABLESPACES WHERE NAME='wjqtest/employees';
+-------+-------------------+---------------+-----------+----------------+
| SPACE | NAME | FS_BLOCK_SIZE | FILE_SIZE | ALLOCATED_SIZE |
+-------+-------------------+---------------+-----------+----------------+
| 265 | wjqtest/employees | 4096 | 114688 | 32768 |
+-------+-------------------+---------------+-----------+----------------+
1 row in set (0.00 sec)
 
# ls -l /data/mysql_8306/data/wjqtest/employees.ibd
-rw-r----- 1 mysql mysql 114688 Jan 11 11:22 /data/mysql_8306/data/wjqtest/employees.ibd
 
# du --block-size=1 /data/mysql_8306/data/wjqtest/employees.ibd
32768 /data/mysql_8306/data/wjqtest/employees.ibd

如上:在linux系统上,ls -l employees.ibd,以字节为单位显示明显的文件大小(相当于文件大小)。要查看磁盘上实际分配的空间量(相当于分配的大小),使用du –block-size=1 employees.ibd。–block size=1选项以字节而不是块的形式输入分配的空间,查询的结果和INFORMATION_SCHEMA.INNODB_TABLESPACES记录的结果一致。

页压缩限制和使用说明

* 如果文件系统块大小*2>innodb_页面大小,则禁用页面压缩。 * 驻留在共享表空间(包括系统表空间、临时表空间和常规表空间)中的表不支持页面压缩。 * undo/redo日志表空间不支持页面压缩。 * 使用具有较大InnoDB页面大小和相对较小文件系统块大小的页面压缩功能可能会导致写入放大。例如,最大InnoDB页面大小为64KB,文件系统块大小为4KB,这可能会提高压缩,但也可能会增加对缓冲池的需求,从而增加I/O和潜在的写放大。

小结

在进行表结构设计时,除了进行列的选择外,还需要考虑存储的设计,特别是对于表的压缩功能的设计,总结来说:

* COMPRESS 页压缩适合用于性能要求不高的业务表,如日志表等; * COMPRESS 页压缩内存缓冲池存在压缩和解压的两个页,会影响性能; * 对存储有压缩需求,又希望性能不要有明显退化,推荐使用 TPC 压缩; * 通过 ALTER TABLE 启用 TPC 压缩后,还需要执行命令 OPTIMIZE TABLE 才能立即完成空间的压缩。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-01-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DBA的辛酸事儿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Linux系统服务神器:systemctl的简单配置与使用
以前使用Ubuntu和CentOS,一般使用SysV init(就是以前使用的service)进行进程的开机自启和进程守护。
Mintimate
2022/04/08
7K1
Linux系统服务神器:systemctl的简单配置与使用
centos7上systemd详解 原
CentOS 7继承了RHEL 7的新的特性,如强大的systemd, 而systemd的使用也使得以往系统服务的/etc/init.d的启动脚本的方式就此改变, 也大幅提高了系统服务的运行效率。但服务的配置和以往也发生了极大的不同,同时变的简单而易用了许多。
拓荒者
2019/04/19
1.1K0
Linux系统管理-crond、chkconfig、systemd、unit、target
语法: crontab [options] Options: -e:=edit 编辑用户的计时器设置 -l:=list 列出用户的计时器设置 -r:=remove 删除用户的计时器设置 -u:=user 指定设定计时器的用户
阿dai学长
2019/04/03
1.1K0
Systemd 进程管理工具实战教程
systemd是目前Linux系统上主要的系统守护进程管理工具,由于init一方面对于进程的管理是串行化的,容易出现阻塞情况,另一方面init也仅仅是执行启动脚本,并不能对服务本身进行更多的管理。所以从CentOS 7开始也由systemd取代了init作为默认的系统进程管理工具。
民工哥
2021/03/15
5430
Systemd 进程管理工具实战教程
自启动文件编写。
vim /lib/systemd/system/nginx.service 文件内容:
@凌晨
2020/05/28
1.2K0
systemd进程管理工具实战教程
systemd是目前Linux系统上主要的系统守护进程管理工具,由于init一方面对于进程的管理是串行化的,容易出现阻塞情况,另一方面init也仅仅是执行启动脚本,并不能对服务本身进行更多的管理。所以从CentOS 7开始也由systemd取代了init作为默认的系统进程管理工具。
子润先生
2021/06/17
7280
Linux系统-systemd
作者介绍:简历上没有一个精通的运维工程师。请点击上方的蓝色《运维小路》关注我,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。
运维小路
2024/11/01
1030
Linux系统-systemd
linux系统管理及安全管理——systemctl/systemd
该脚本使用于启动多个mysql实例的环境,如果想管理单个MySQL进程,只需要将“%i”换成具体的参数就好(mysql单实例管理可参考:http://blog.csdn.net/shen2308/article/details/78492460)。
阿dai学长
2019/04/03
5.6K0
linux如何设置nginx、mysql开机自启动
有很多小伙伴都没有一个统一的设置nginx和mysql开机自启动的方式,今天我就将我的统一开机自启动格式分享给大家
Hunter@Miracle
2022/08/26
8K0
linux添加开机启动脚本 原
0——关机, 1——单用户,就是我们之前修改root账户密码的模式, 2——多用户模式,但比3模式少了一个nfs服务 3——多用户命令行模式,最常用 4——保留级别暂时没用, 5——图形模式, 6——重启
晓歌
2018/09/28
1.7K0
linux添加开机启动脚本
                                                                            原
Nginx封装为CentOS7的服务
编译安装好nginx后,正常启动方式 例如我的安装目录是/usr/local/nginx 修改配置后重新加载生效 /usr/local/nginx/sbin/nginx -s reload 重新打开日志文件 /usr/local/nginx/sbin/nginx -s reopen 测试nginx配置文件是否正确 /usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf 启动nginx /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf 快速停止nginx /usr/local/nginx/sbin/nginx -s stop 完整有序的停止nginx /usr/local/nginx/sbin/nginx -s quit 注:stop和quit的区别在于 quit是一个优雅的关闭方式,Nginx在退出前完成已经接受的连接请求 Stop 是快速关闭,不管有没有正在处理的请求。
飞狗
2018/09/10
6400
CentOS6/7 配置守护进程
CentOS6中转用Upstrat代替以前的init.d/rcX.d的线性启动方式。
Chester Chen
2022/12/19
1K0
Linux Systemd 实战
对于那些支持 Systemd 的软件,安装的时候,会自动在/usr/lib/systemd/system目录添加一个配置文件。
为为为什么
2022/08/06
1.7K0
【笔记】Linux安装Nginx相关步骤,备忘
本来尝试了Docker的,但是由于一些原因,不太方便,还是选择原生 的nginx安装
无道
2021/07/19
3170
【Linux】自启动配置
自启动配置是确保系统服务在启动时能够自动运行的关键步骤。在Linux系统中,systemd是一个先进的初始化系统和服务管理器,它通过配置单元文件(unit files)来定义服务的启动行为,包括依赖关系和启动顺序。以下是关于自启动配置的一些关键概念和步骤:
人不走空
2024/02/21
4220
systemd设置nginx开机自启动
服务器每次重启,都需要手动启动一些服务,这不是一个程序员可以忍受的,难怪大家都喜欢写脚本。CentOS7之后已不再使用chkconfig管理启动项,而是使用systemd。
胡齐
2020/08/11
7.1K1
systemd 使用教程【转】
http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html
保持热爱奔赴山海
2019/09/18
1.1K0
systemd 使用教程【转】
编写一个服务systemd的启动方式
工作中遇到了一个问题,开发人员编写了一个程序,想要开机自启动,一开始还想偷点懒直接把启动命令直接写到rc.local,后来发现毛病太多,索性直接编写一个systemd文件来控制启动
dgds
2023/08/02
5230
Centos8上安装Nginx
  命令: wget http://nginx.org/download/nginx-1.20.2.tar.gz
Se7eN_HOU
2021/11/24
8490
Centos8上安装Nginx
centos7如何添加开机启动项?
1.系统服务管理命令,如果是通过yum安装的软件,开机启动脚本,已经自动创建好了,直接执行如下命令
超蛋lhy
2019/06/05
2.5K0
相关推荐
Linux系统服务神器:systemctl的简单配置与使用
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档