MySQL压缩的使用场景和解决方案
-
客户端与服务端传输的数据量太大需要压缩,用于节省带宽。 -
当某个表或某列数据量大时,对某列进行压缩(官方指出可进行对表和列的压缩)。
-
当用于日志记录,序列化或json化大量item数据时对此列进行压缩。 -
数据压缩以提高CPU利用率为代价,实现了更小的数据库大小、减少I/O和提高吞吐量
https://docs.gitcode.net/mysql/guide/the-innodb-storage-engine/innodb-compression-usage.html
压缩表不能存储在InnoDB系统表空间(日常我们优先选择InnoDB存储引擎的)。
通用表空间可以包含多个表,但压缩表和未压缩表不能在同一个通用表空间中共存(对于数据库也太不友好,不好管理了)。
压缩适用于整个表及其所有关联索引,而不适用于单个行,尽管有子句名称ROW_FORMAT.
InnoDB不支持压缩临时表。什么时候innodb_strict_mode已启用(默认),创建临时表如果返回错误ROW_FORMAT=压缩要么KEY_BLOCK_SIZE被指定。如果innodb_strict_mode被禁用,发出警告并使用非压缩行格式创建临时表。同样的限制适用于更改表对临时表的操作。
那么我们直接进入压缩列的部分。
MySQL的列压缩
MySQL 针对列的压缩目前直接的方案并不支持,但是在业务层面使用 MySQL 提供的压缩和解压函数来针对列进行压缩和解压操作。也就是要对某一列做压缩,就需要在写入的时候调用 COMPRESS 函数对那个列的内容进行压缩,然后存放到对应的列。读取的时候,使用 UNCOMPRESSED 函数对压缩的内容进行解压缩
适用场景:针对MySQL中某个列或者某几个列数据量特别大,一般都是varchar、text、char等数据类型(如果内容包含emoj表情则注意需要使用编码类型为utf8mb4)。
压缩算法
一些操作系统在文件系统级别实现压缩。文件通常被分成固定大小的块,这些块被压缩成可变大小的块,这很容易导致碎片。每次修改块内的某些内容时,都会在将整个块写入磁盘之前对其进行重新压缩。这些特性使得这种压缩技术不适合在更新密集型数据库系统中使用。
innodb 压缩借助的是著名的 zlib 库,采用 L777 压缩算法,这种算法在减少数据大小和 CPU 利用方面很成熟高效。同时这种算法是无损的,因此原生的未压缩的数据总是能够从压缩文件中重构,LZ777 实现原理是查找重复数据的序列号然后进行压缩,所以数据模式决定了压缩效率,一般而言,用户的数据能够被压缩 50%以上。
Java的工具包(java.util.zip)下提供了Inflater和Deflater工具类来实现压缩和解压缩处理
支持的字段类
压缩 BLOB、VARCHAR 和 TEXT 列
在 InnoDB 表中,BLOB、VARCHAR 和 TEXT不属于主键的列可以存储在单独分配的溢出页面.我们将这些列称为页外栏.它们的值存储在溢出页面的单链表中,压缩后的数据不能直接在SQL中查询显示,所以建议使用在记录列上。
mybaits-plus 处理方式类型处理器,用于 JavaType 与 JdbcType 之间的转换,用于 PreparedStatement 设置参数值和从 ResultSet或CallableStatement中取出一个值,mybaits-plus内置常用类型处理器通过TableField注解快速注入到 mybatis 容器中。
@Data@Accessors(chain = true)@TableName(autoResultMap = true)public class User { private Long id; ... /** * 注意!!必须开启映射注解 * * @TableName(autoResultMap = true) * * 以下两种类型处理器,二选一 也可以同时存在 * * 注意!!选择对应的 JSON 处理器也必须存在对应 JSON 解析依赖包 */ @TableField(typeHandler = JacksonTypeHandler.class) // @TableField(typeHandler = FastjsonTypeHandler.class) private OtherInfo otherInfo; }
那么针对本次的压缩类型来说则指定为TypeHandler来实现BaseTypeHandler(org.apache.ibatis.type.BaseTypeHandler)
实例SQL
select length(compress('你好👌')); -- 返回压缩后的字节数select convert(uncompress(compress('hello 👌')) using 'utf8mb4')insert into table xxx (对要压缩的字段使用compress())
对比压缩前后数据
SELECT UNCOMPRESSED_LENGTH(content) AS length, LENGTH(content) AS compress_length, UNCOMPRESS(content), content FROM `test_compress`
注意:当字段类型为longtext时不适用,表结构虽然为utf8mb4但仍旧报错
对于日常请求入参出参的记录表来说,如果长时间不使用该字段做任何业务逻辑,短暂问题也会通过ELK来查询问题,建议对参数字段进行压缩,能够大大减少内存使用,并通过调节设置参数减少使用CPU资源。
--- 我站在十字路口,如同站在时间长河的上游,转念回首,它仿佛踏着神辉在游走。
- 点赞
- 收藏
- 关注作者
评论(0)