MySQL 压缩数据包详解

MySQL 压缩数据包详解

1. ​整体结构

MySQL 压缩数据包由两部分组成:

  • 压缩包头 (Compressed Packet Header)​:固定 7 字节
  • 有效载荷 (Payload)​:压缩或未压缩的实际数据
diff 复制代码
plaintext
复制
+---------------------+---------------------+
| 压缩包头 (7 字节)   |     有效载荷        |
+---------------------+---------------------+

2. ​压缩包头详解

字段 大小 说明
压缩后长度 3 字节 大端序存储,表示有效载荷的实际长度​(即整个包长度减 7 字节包头)
序列号 1 字节 独立于普通数据包的序列号,按压缩包递增
未压缩长度 3 字节 关键标志位: - >0:表示压缩数据 - =0:表示未压缩数据

3. ​有效载荷的两种形式

​(1) 压缩数据 (未压缩长度 > 0)​

  • 使用 zlib 的 DEFLATE 算法(RFC 1951)压缩
  • 可包含多个 MySQL 数据包(协议允许合并压缩多个包)
  • 解压后数据 = 原始 MySQL 包(含 4 字节包头)

​(2) 未压缩数据 (未压缩长度 = 0)​

  • 直接存储原始 MySQL 数据包
  • 触发条件:数据长度 < MIN_COMPRESS_LENGTH(默认 50 字节)

4. ​关键机制解析

​(1) 多包合并压缩

scss 复制代码
plaintext
复制
原始包 1 (18 字节)       原始包 2 (25 字节)
       ↓                       ↓
      +---------------------------+
      |      合并压缩 (单个压缩包)     |
      +---------------------------+

优势:减少小包场景下的网络开销

​(2) 长度限制规避

当原始包长度 ≥ 16MB(2²⁴ - 1)时:

  • 压缩包头无法表示未压缩长度(仅 3 字节)
  • 强制拆分为多个压缩包发送

​(3) 序列号独立

  • 压缩包序列号与普通包序列号各自独立计数
  • 每个连接维护两套序列号

5. ​实战案例解析

​(1) 压缩示例:`SELECT "0123..." (46 字节)​

makefile 复制代码
plaintext
复制
原始包: 
  2e 00 00 00 03 ... 35 22  (46 字节)

压缩包:
  22 00 00 00   → 压缩后长度 = 34 字节 (0x22)
  32 00 00      → 未压缩长度 = 50 字节 (含包头膨胀)
  78 9c ... 6c  → DEFLATE 压缩数据

✓ 压缩率:46 → 34 字节(节省 26%)

​(2) 未压缩示例:SELECT 1 (13 字节)​

makefile 复制代码
plaintext
复制
压缩包:
  0d 00 00 00   → 有效载荷长度 = 13 字节
  00 00 00      → 未压缩长度 = 0 (标志位)
  09 00 00 00   → 原始包头 (长度 9 + 序列号 0)
  03 53 45 ...  → "SELECT 1" ASCII

✓ 因长度 < 50 字节,直接透传

​(3) 大包拆分场景

原始包长度 16MB - 2 字节时:

  1. 原始长度:0xFFFFFE (16,777,214 字节)
  2. 添加 4 字节包头 → 总长 0x1000002 (16,777,218 字节)
  3. 超过 3 字节表示范围 (0xFFFFFF)​ → 必须拆包

6. ​核心实现逻辑

ini 复制代码
c
复制
// 伪代码:压缩包构建
void build_compressed_packet() {
  if (original_size < MIN_COMPRESS_LENGTH) {
    header.uncompressed_len = 0;  // 未压缩标志
    payload = original_data;      // 原始数据透传
  } else {
    header.uncompressed_len = original_size;
    payload = zlib_compress(original_data); // DEFLATE 压缩
  }
  
  header.compressed_len = payload.size();
  header.seq_id = compressed_seq++; // 独立序列号递增
}

7. ​设计要点总结

特性 说明
按需压缩 MIN_COMPRESS_LENGTH 避免小包负压缩
协议兼容 未压缩包含完整 MySQL 包头
并行序列 压缩/普通包序列号独立计数
大包拆分 处理 16MB+ 数据边界
高效合并 单压缩包承载多协议包

注:实际实现参考 MySQL 源码 sql-common/compression.cccompress_packet() 函数

相关推荐
汪子熙2 小时前
HSQLDB 数据库锁获取失败深度解析
数据库·后端
无色海5 小时前
mysql连接生命周期-连接阶段
数据库
无色海6 小时前
MySQL协议中的TLS实现
数据库
weixin_418007607 小时前
SpringJPA统计数据库表行数及更新频率
数据库
2301_767233227 小时前
怎么优化MySQL中的索引
数据库·mysql
海尔辛7 小时前
防御性安全:数字取证
数据库·安全·数字取证
繢鴻8 小时前
数据库优化实战分享
数据库
Cachel wood9 小时前
后端开发:计算机网络、数据库常识
android·大数据·数据库·数据仓库·sql·计算机网络·mysql
暗离子跃迁9 小时前
达梦数据库单机部署dmhs同步复制(dm8->kafka)
linux·运维·数据库·分布式·学习·kafka·达梦数据库