LOB在RAC中变慢的根本原因是默认ENABLE STORAGE IN ROW、小CHUNK及缺失LOGGING控制,导致频繁缓存融合争用与redo膨胀;应设DISABLE STORAGE IN ROW、CHUNK为DB_BLOCK_SIZE整数倍、PCTVERSION 10–20,并优选SecureFile以支持DEDUPLICATE、在线COMPRESS和细粒度LOGGING。
LOB字段为什么在RAC里容易变慢?
oracle rac中lob(尤其是blob/clob)性能下降,根本原因不是rac本身,而是默认enable storage in row + chunk小 + 缺少logging控制,导致大量跨实例的缓存融合(cache fusion)争用和redo膨胀。真实场景中,一个update语句修改10kb的clob字段,可能触发几十次gc current block 2-way等待。
- 默认
CHUNK大小是8KB,但实际分配按DB_BLOCK_SIZE对齐,小LOB仍存于行内,大LOB则分散到LOB segment,引发额外I/O和全局资源竞争 - RAC节点间共享
LOBINDEX结构,高并发INSERT/UPDATE易出现enq: TX - row lock contention或enq: UL - contention -
NOLOGGING操作虽快,但在RAC中可能导致备库/闪回丢失数据,且LOB的NOLOGGING不作用于索引段,仍写redo
怎么设置LOB存储参数才适合RAC?
关键不是“调大”,而是让LOB行为可预测、减少跨节点同步开销。重点调整三个参数:CHUNK、PCTVERSION、RETENTION,并强制DISABLE STORAGE IN ROW。
-
CHUNK设为DB_BLOCK_SIZE整数倍(如8192),避免跨块切分;若LOB普遍>4MB,可设为65536,减少chunk数量和index深度 -
PCTVERSION建议设为10–20(非默认0),防止高并发更新时产生过多旧版本LOB数据块,避免ORA-22924(snapshot too old) - 必须显式指定
DISABLE STORAGE IN ROW,否则即使LOB>4000字节,仍可能因内部优化存入行内,加剧buffer busy waits - 创建示例:
CREATE TABLE doc_store ( id NUMBER, content CLOB ) LOB(content) STORE AS SECUREFILE doc_lob ( CHUNK 8192 PCTVERSION 15 DISABLE STORAGE IN ROW RETENTION MIN LOGGING );
SecureFile比BasicFile在RAC里强在哪?
BasicFile在RAC中本质是“伪共享”——每个节点维护自己的LOB缓存和锁管理逻辑,冲突多、诊断难;SecureFile则由RAC-aware的底层引擎统一调度,尤其在并发读写和压缩场景下差异明显。
- SecureFile支持
DEDUPLICATE,相同LOB内容只存一份,大幅降低RAC节点间重复传输量 -
COMPRESS MEDIUM/HIGH在SecureFile中是在线、无锁的,BasicFile压缩需ALTER TABLE ... MOVE,触发全表锁+跨节点重分布 - SecureFile的
ENCRYPT使用列级密钥,加密/解密不依赖实例本地wallet,避免RAC节点间密钥不一致导致ORA-28365 - BasicFile的
LOGGING开关粒度粗(整个segment),SecureFile可精确到LOB操作级别(如DBMS_LOB.WRITEAPPEND是否记redo)
应用层怎么安全地并发读写LOB?
直接SELECT ... FOR UPDATE查LOB再DBMS_LOB.WRITE,在RAC中极易死锁或超时;正确做法是绕过行级锁,用乐观控制+原子操作。
- 写入优先用
DBMS_LOB.CREATETEMPORARY+DBMS_LOB.CONVERTTOBLOB等批量接口,避免逐字节WRITE引发长时间持有LOB locator - 更新LOB时,用
UPDATE ... SET lob_col = :new_lob WHERE id = :id AND version = :old_version配合应用层version字段,失败则重试,不依赖数据库锁 - 读取大LOB不要用
SELECT lob_col FROM ...直取,改用DBMS_LOB.SUBSTR(lob_col, 32767, 1)分片拉取,降低单次GC流量 - 禁止在PL/SQL循环里反复
DBMS_LOB.READ小块数据——每次调用都触发一次LOB locator解析和远程块请求,换成DBMS_LOB.OPEN+批量READ能降80%+ GC等待
真正棘手的从来不是LOB有多大,而是应用没意识到:RAC里每个DBMS_LOB调用背后,都可能是一次跨节点的块传输和全局队列争用。

















