LOB压缩不能通过DBMS_LOB函数实现,必须在表定义时指定SECUREFILE+COMPRESS/DEDUPLICATE属性;ALTER TABLE分两步启用可避免长时间锁表;DEDUPLICATE仅对同列完全相同LOB生效;压缩后读取需实时解压,性能下降3–5倍。
LOB压缩在PL/SQL里根本不能靠DBMS_LOB函数直接做
oracle的dbms_lob包不提供任何压缩或去重接口,compress、dedupe这类操作不是pl/sql运行时能力,而是存储层特性。你写个dbms_lob.substr或dbms_lob.copy,对lob内容本身毫无压缩效果。
常见错误现象:在PL/SQL块里反复调用DBMS_LOB.WRITE或拼接CLOB,以为“少写点就省空间”——实际LOB段物理大小完全不受影响,甚至因重复写入引发更多碎片。
- 真正起作用的是表定义时指定
SECUREFILE+COMPRESS或DEDUPLICATE属性,且必须在创建表/修改列时启用 - 已存在的
BASICFILELOB无法在线转为SECUREFILE COMPRESS,必须重建表或使用DBMS_REDEFINITION -
COMPRESS HIGH比COMPRESS MEDIUM多压10–15%空间,但CPU开销翻倍,OLTP场景慎用
如何安全启用SECUREFILE COMPRESS而不锁表太久
直接ALTER TABLE ... MODIFY LOB(...) (COMPRESS HIGH)会锁全表,尤其大表可能阻塞业务数小时。关键在于分两步走,把高成本操作挪到低峰期。
- 先执行
ALTER TABLE t MODIFY LOB(col) (STORE AS SECUREFILE)(无压缩),这步只改数据字典,秒级完成 - 再执行
ALTER TABLE t MODIFY LOB(col) (COMPRESS HIGH),此时Oracle才真正扫描并压缩现有LOB数据——这步可加ONLINE(12cR2+)避免DML阻塞 - 若版本低于12cR2,用
DBMS_LOB.SETOPTIONS无效,该函数只影响新写入LOB,对存量数据无感
DEDUPLICATE对重复大附件的实际效果很有限
DEDUPLICATE只对完全相同的LOB值生效,且仅在同一个LOB列内比对。它不是文件级去重,也不跨行、跨表、跨列。
- 两个用户上传同一张
report.pdf,但一个存为CLOB一个存为BLOB,不会去重 - 同一文档被
UTL_RAW.CAST_TO_RAW和UTL_I18N.STRING_TO_RAW不同方式编码后写入,哈希值不同,照样不识别 - 启用后首次写入重复内容时,Oracle需计算SHA-1校验和并查全局dedupe hash表,单次写入延迟增加0.5–2ms,高并发插入敏感
压缩后LOB读取变慢是常态,别指望“无损加速”
启用了COMPRESS的SECUREFILE,每次DBMS_LOB.READ或SQL中SELECT该LOB列,Oracle都得实时解压。这不是缓存问题,是设计使然。
- 实测10MB BLOB开启
COMPRESS HIGH后,DBMS_LOB.GETLENGTH返回的仍是原始长度,但V$SECUREFILE_SHRINK显示物理占用降了60%,代价是读取耗时涨3–5倍 - 如果应用频繁
DBMS_LOB.INSTR搜索LOB内容,压缩反而让性能更差——因为没法在压缩态下做模式匹配,必须全量解压到PGA - 想绕过解压开销?唯一办法是提前把关键字段(如PDF第一页文本)抽出来存为普通
VARCHAR2列,别依赖LOB原生检索
SECUREFILE的压缩和去重不是开关一按就万事大吉的事,它把空间换算成CPU、内存和延迟,而这些代价在测试环境里往往看不出来。










