PAYATHON 2026

MariaDB/MySQL 的 BLOB 数据存在哪里,如何占用磁盘空间?

数据小许

如果表使用 InnoDB,BLOB 数据保存在表空间中。较短的数据可以放在行记录内,较长的数据可能放到溢出页,由行记录保存内部指针。数据库通常不会为每个 BLOB 单独创建文件,也不会在字段中保存可供应用使用的文件名。具体布局取决于存储引擎、ROW_FORMAT、页大小和整行数据的长度。

BLOB 在 InnoDB 中怎样存储?

以 ROW_FORMAT=DYNAMIC 为例:

  • 行记录能容纳数据时,BLOB 可以保留在行内。
  • 如果整行过大,需要移出部分变长列,被选中的 BLOB 值会完整存入溢出页,行内保留一个 20 字节的指针。
  • 如果一个溢出页放不下,数据会占用多个溢出页。

不能只根据“超过 255 bytes”判断 BLOB 是否会存到行外。DYNAMIC 对 BLOB/TEXT 的行外存储候选值有长度条件,但是否真正移出还取决于整行大小。COMPACT 的行为有所不同:移到行外的长值仍会在行内保留一段前缀。参见 MariaDB 的 DYNAMIC 行格式说明。

这些规则适用于 InnoDB。如果表使用 MyISAM、Aria 或其他存储引擎,需要按对应引擎判断,不能仅凭 BLOB 类型推断物理布局。

数据最终在哪个文件里?

InnoDB 的表空间文件保存表数据和索引。对于 MariaDB 中创建时采用独立表空间的普通 InnoDB 表,通常会有对应的 .ibd 文件;采用系统表空间的表则把数据存入共享的系统表空间。一个表空间中可以包含大量记录及其 BLOB 数据。参见 MariaDB 的独立表空间说明。

应用通过 SQL 读写 BLOB,页分配和内部引用由 InnoDB 管理。如果应用自行保存文件并在表中记录路径,就需要自行维护文件与数据库记录的一致性。

声明 BLOB 会为每行预留约 65 KB 吗?

不会。普通 BLOB 的最大长度是 65,535 字节,实际值可以短得多。MariaDB 给出的 BLOB/TEXT 类型级存储需求是 L + 2 字节,其中 L 是实际数据的字节数。这不表示每行都预分配最大容量,最终磁盘占用也不一定恰好等于 L + 2。参见 BLOB 类型说明和数据类型存储需求。

实际占用还包括行记录、页头、索引、页内空闲空间和表空间分配等开销。固定容量设备还要为日志和运行期间的临时空间留出预算,不能只累加字段长度。

存储文本应该选 BLOB 还是 TEXT?

如果内容是需要按字符集解释、比较和排序的文本,通常选择 TEXT;如果需要保存原始字节,选择 BLOB。普通 TEXT 的容量上限同样受 65,535 字节限制,多字节字符会减少可存储的字符数。参见 MariaDB 的 TEXT 说明。

在支持 DYNAMIC 行格式的环境中,可以用下面的表结构作为测试起点:

CREATE TABLE embedded_text (
    id INT UNSIGNED NOT NULL PRIMARY KEY,
    body TEXT NOT NULL
) ENGINE=InnoDB
  ROW_FORMAT=DYNAMIC
  DEFAULT CHARSET=utf8mb4;

如果要求按字节原样保存,可以把 body TEXT 改为 body BLOB。VARCHAR 也可以超过 255 字节,是否适用取决于长度、字符集和整行限制;超过 255 字节并不意味着必须使用 BLOB。

固定容量系统怎样评估空间?

先确认实际表结构和配置,把 your_table 替换成目标表名:

SELECT VERSION();
SHOW CREATE TABLE your_table;
SHOW TABLE STATUS WHERE Name = 'your_table';
SHOW VARIABLES LIKE 'innodb_page_size';
SHOW VARIABLES LIKE 'innodb_file_per_table';

重点看表的 Engine 和 Row_format。当前 innodb_file_per_table 的值主要说明新建表的配置,不能单凭它判断历史表的存放位置。

再使用有代表性的文本长度和实际记录数量填充测试表,统计有效内容的字节数:

SELECT
    COUNT(*) AS row_count,
    SUM(OCTET_LENGTH(body)) AS payload_bytes,
    AVG(OCTET_LENGTH(body)) AS avg_payload_bytes,
    MAX(OCTET_LENGTH(body)) AS max_payload_bytes
FROM embedded_text;

将结果与 SHOW TABLE STATUS 的 Data_length、Index_length 及文件系统实际占用一起比较。表状态中的空间指标具有引擎相关含义,并非每个 BLOB 精确占用的统计;共享表空间下的 Data_free 也不能直接当作该表的独占空闲空间。参见 SHOW TABLE STATUS 字段说明。

测试还应覆盖文本更新、删除和重新插入,因为稳定运行后的占用可能与刚完成批量插入时不同。仅凭字段定义,无法算出这套设备最终能保存多少条记录。

是否改为外部文件,需要比较相同数据量下两种方案的实际占用,同时考虑文件系统分配开销,以及文件与数据库记录同步的维护成本。原问题没有提供引擎、行格式和数据长度分布,因此无法断言哪种方案一定更省空间。

备注:内容仅供参考。