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.cc 的 compress_packet() 函数

相关推荐
可乐ea3 分钟前
Agent 评测换判据:用终态数据库状态判定任务是否完成
数据库·ui·oracle·mcp工具·agent评测·终态断言·智能体可靠性
l1t8 分钟前
DeepSeek总结的一个不含数据的 DuckDB 数据库
服务器·数据库·duckdb
PaperData1 小时前
2007-2020年税收调查面板数据
数据库
程序员清风1 小时前
CSV、Excel 与数据库数据读取实践
数据库·oracle·excel
GEO实战经验分享2 小时前
GEO技术与工具全景:从监测仪表盘到Schema的实战指南
数据库
一个天蝎座的程序猿2 小时前
IoTDB集群扩容:从慌乱到从容的经验分享
数据库
小小龙学IT3 小时前
Python SQLAlchemy 2.0 深度解析:从 Core 到 ORM 的数据访问双引擎
开发语言·数据库·python
DongQiShanRen3 小时前
裁决台账双向互校(上):名册与实物的第一道对账
java·linux·运维·数据库·人工智能·自然语言处理·数据挖掘
ShineWinsu3 小时前
对于Redis:AOF持久化的解析
linux·数据库·redis·缓存·面试·持久化·aof
仍然.3 小时前
Redis---集群
数据库·redis·缓存