MySQL压缩的使用场景和解决方案

举报
赵KK日常技术记录 发表于 2023/06/30 23:54:10 2023/06/30
【摘要】  技术点来源于每周技术分享会,对于MySQL压缩的技术方案进行了分享,针对本次分享思考是否使用技术方案改造,并代入demo。压缩相关的场景客户端与服务端传输的数据量太大需要压缩,用于节省带宽。当某个表或某列数据量大时,对某列进行压缩(官方指出可进行对表和列的压缩)。当用于日志记录,序列化或json化大量item数据时对此列进行压缩。数据压缩以提高CPU利用率为代价,实现了更小的数据库大小、减...
 技术点来源于每周技术分享会,对于MySQL压缩的技术方案进行了分享,针对本次分享思考是否使用技术方案改造,并代入demo。
压缩相关的场景
  1. 客户端与服务端传输的数据量太大需要压缩,用于节省带宽。
  2. 当某个表或某列数据量大时,对某列进行压缩(官方指出可进行对表和列的压缩)。
  3. 当用于日志记录,序列化或json化大量item数据时对此列进行压缩。
  4. 数据压缩以提高CPU利用率为代价,实现了更小的数据库大小、减少I/O和提高吞吐量
翻阅大量资料才找到官网出处,附链接,我在《高性能MySQL》第三版中也并未找到此章节。

图片

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资源。

    --- 我站在十字路口,如同站在时间长河的上游,转念回首,它仿佛踏着神辉在游走。



,时长00:07


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。