MyISAM存BLOB会全表锁,InnoDB分内联与溢出存储;查大BLOB应避免SELECT*,索引需抽特征到独立列,备份复制时建议外存大对象。

MyISAM 存储 BLOB 时会锁整个表
MyISAM 对 BLOB 字段没有行级锁支持,哪怕只更新一条记录的 BLOB,也会触发全表写锁。这意味着并发插入或更新会被阻塞,尤其在中高并发写入场景下,SHOW PROCESSLIST 里常看到大量 Locked 状态。
实操建议:
- 如果业务有频繁更新
BLOB(比如用户头像、文档内容),别用 MyISAM - 即使只读为主,也要注意
OPTIMIZE TABLE或REPAIR TABLE会锁表,影响可用性 - MyISAM 的
BLOB实际存储在数据文件里,但不压缩、不延迟加载,读取大对象时内存和磁盘 I/O 压力都直接拉满
InnoDB 的 BLOB 存储分内联与溢出两种模式
InnoDB 默认对小于约 768 字节的 BLOB 值尝试内联存储(存进主记录页),超过则转为溢出页(off-page)存储,主记录只保留 20 字节指针。这个阈值受 innodb_page_size 和行格式影响——ROW_FORMAT=COMPACT 下是 768 字节,ROW_FORMAT=DYNAMIC 或 COMPRESSED 下可存更长的前缀(默认 768,但允许配置 innodb_large_prefix)。
常见错误现象:SELECT * 查询慢,不是因为网络或索引,而是每次都要跨页读溢出段;EXPLAIN 看不出问题,但 SHOW ENGINE INNODB STATUS 里能看到大量 pages read 和 overflow pages。
实操建议:
- 查大对象时,明确指定字段名,避免
SELECT *拉取溢出页 - 写入前评估平均大小:若多数
BLOB> 1KB,建议设ROW_FORMAT=DYNAMIC并确认innodb_large_prefix=ON -
INSERT时若批量写入含大BLOB的行,注意事务日志(ib_logfile)可能迅速膨胀,甚至触发Lock wait timeout exceeded
查询 BLOB 字段时,WHERE 条件不能用全文索引以外的索引加速
InnoDB 不支持对 BLOB 列建普通 B+Tree 索引(除非指定前缀长度,如 INDEX(blob_col(100))),而 MyISAM 虽然支持前缀索引,但对 BLOB 的前缀匹配极不可靠——二进制内容导致排序和比较行为异常,LIKE 'xxx%' 可能漏结果。
使用场景:想按文件哈希(如 SHA2(file_content, 256))快速定位,别把哈希值存在 BLOB 里再索引它;应单独建 CHAR(64) 字段存哈希,加普通索引。
实操建议:
- 需要条件过滤
BLOB内容?先抽特征到独立列,再索引 - 真要搜二进制内容,只能靠
FULLTEXT(仅限TEXT类型,且BLOB不支持)或应用层处理 - 用
LENGTH(blob_col) > 1024这类判断是可行的,优化器能走索引(如果该列有统计信息且非空)
备份与复制时,BLOB 会让 mysqldump 和 binlog 显著变大
mysqldump 默认把 BLOB 转成十六进制字符串(如 X'47494638...' ),体积翻倍;binlog 中 ROW 格式会完整记录变更前后的 BLOB 值,一次 10MB 文件更新,可能产生 20MB+ 的 binlog 事件,拖慢从库重放速度,还容易填满 max_binlog_size。
性能影响:主从延迟升高、SHOW SLAVE STATUS 中 Seconds_Behind_Master 跳变、binlog_cache_use 指标飙升。
实操建议:
- 导出不含
BLOB的结构和元数据:用mysqldump --no-data+ 单独导出文件路径 - 复制链路上,考虑把大对象移到外部存储(如 S3、本地 NFS),数据库只存 URL 和元信息
- 若必须存库内,至少关掉
binlog_row_image=FULL改为MINIMAL(5.6+),减少 binlog 体积
真正麻烦的不是“能不能存”,而是“一动就牵全身”——改个字段类型、加个索引、切个主从,BLOB 都会突然冒出来说话。



















