Oracle LOB使用入门和简单使用,提供学习用的测试用例!
Oracle LOB字段使用方法与数据泵迁移实战指南
Oracle数据库中的LOB(Large Object)字段是存储大型非结构化数据的理想选择,支持高达4GB的文本、图像、音频、视频等数据存储。本问简单介绍创建含LOB/CLOB字段
的表结构、批量插入10万行数据、拆分LOB表结构,并提供验证数据完整性的测试用例,适合复习或者学习新知识点用。
一、创建含LOB/CLOB字段的表结构
创建含LOB字段的表时,应根据业务需求选择适当的LOB类型,并合理配置存储参数以优化性能。对于大型文本数据,CLOB是最常用的选择;对于二进制数据,BLOB更为合适。以下是创建含CLOB字段的表的示例,采用SecureFiles存储方式并优化存储参数:
-- 创建专用表空间用于存储LOB数据
sqlplus / as sysdba
CREATE TABLESPACE lob_tbs
DATAFILE '/oradata/ora11g/lob_tbs01.dbf' SIZE 100M AUTOEXTEND ON MAXSIZE UNLIMITED
LOGGINGExtent Management LocalSegment Space Management Auto;-- 创建含CLOB字段的表,使用SecureFiles存储并优化参数
CREATE TABLE lob_table (id NUMBER PRIMARY KEY,text_data CLOB,binary_data BLOB,created_at DATE DEFAULT SYSDATE
)
TABLESPACE users
LOB (text_data) STORE AS SECUREFILE (TABLESPACE lob_tbsENABLE STORAGE IN ROWCHUNK 8192PCTVERSION 5COMPRESS HIGHDEDUPLICATENOCACHELOGGING
)
LOB (binary_data) STORE AS SECUREFILE (TABLESPACE lob_tbsENABLE STORAGE IN ROWCHUNK 8192PCTVERSION 5COMPRESS HIGHDEDUPLICATENOCACHELOGGING
);
关键参数解析:
- SecureFiles:Oracle 11g引入的新存储方式,相比BasicFile提供了更好的性能和更多高级功能
- TABLESPACE lob_tbs:将LOB数据单独存储到专用表空间,避免与常规表数据竞争I/O资源
- ENABLE STORAGE IN ROW:允许小于4KB的LOB值存储在行内,提升小数据访问效率
- CHUNK 8192:设置为8KB(与数据库块大小一致),避免存储碎片
- PCTVERSION 5:将版本空间比例从默认10%降至5%,减少空间浪费
- COMPRESS HIGH:启用高级压缩,可节省约40-60%的存储空间
- DEDUPLICATE:启用去重功能,自动检测并合并重复数据,进一步节省存储空间
- NOCACHE:对于只读或低频更新的LOB数据,禁用缓存可减少内存占用
- LOGGING:启用日志记录,确保数据完整性和可恢复性
二、批量插入10万行测试数据
对于大型LOB数据的批量插入,直接逐行插入效率低下,应采用PL/SQL批量操作方法,结合临时LOB和分批次提交机制,以提高插入效率。
-- 创建存储过程,批量插入10万行数据
CREATE OR REPLACE PROCEDURE insert_lob_data(p_rows IN NUMBER := 100000) IS-- 定义用于批量插入的集合类型TYPE t_ids IS TABLE OF NUMBER;TYPE t_clobs IS TABLE OF CLOB;v_ids t_ids;v_clobs t_clobs;v_buffer VARCHAR2(32767);v_max_length NUMBER := 5000; -- 每个CLOB数据的平均长度v_batch_size NUMBER := 1000; -- 每批插入的行数v_start_time TIMESTAMP := SYSTIMESTAMP;v_start NUMBER;v_end NUMBER;v_current_row NUMBER := 1;
BEGIN-- 使用 EXECUTE IMMEDIATE 执行 DDLEXECUTE IMMEDIATE 'ALTER TABLE lob_table NOLOGGING';DBMS_OUTPUT.PUT_LINE('Generating LOB data and IDs for batches...');-- 生成随机数据缓冲区(使用英文字符避免乱码)v_buffer := DBMS_RANDOM.STRING('x', 32767); -- 注意:'x' 表示大小写字母+数字-- 分批次处理,避免一次性将所有数据加载到内存FOR batch_num IN 1..CEIL(p_rows / v_batch_size) LOOPv_start := (batch_num - 1) * v_batch_size + 1;v_end := LEAST(batch_num * v_batch_size, p_rows);-- 初始化当前批次的集合v_ids := t_ids();v_clobs := t_clobs();-- 为当前批次生成数据FOR i IN v_start..v_end LOOP-- 扩展集合大小v_ids.EXTEND;v_clobs.EXTEND;-- 设置IDv_ids(v_ids.LAST) := i;-- 创建并填充临时CLOBDBMS_LOB.CREATETEMPORARY(v_clobs(v_clobs.LAST), TRUE);DECLAREv_written NUMBER := 0;v_chunk NUMBER := 32767;v_to_write NUMBER;v_current_buffer VARCHAR2(32767);BEGINWHILE v_written < v_max_length LOOPv_current_buffer := SUBSTR(v_buffer, 1, LEAST(32767, v_max_length - v_written));v_to_write := LENGTH(v_current_buffer);DBMS_LOB.WRITEAPPEND(v_clobs(v_clobs.LAST), v_to_write, v_current_buffer);v_written := v_written + v_to_write;END LOOP;END;END LOOP;DBMS_OUTPUT.PUT_LINE('Inserting batch ' || batch_num || ' (' || v_start || '-' || v_end || ')...');-- 使用 FORALL 批量插入当前批次的数据FORALL j IN INDICES OF v_idsINSERT INTO lob_table (id, text_data)VALUES (v_ids(j), v_clobs(j));COMMIT;DBMS_OUTPUT.PUT_LINE('Batch ' || batch_num || ' committed.');-- 释放当前批次的临时LOB资源FOR k IN 1..v_clobs.COUNT LOOPIF DBMS_LOB.ISTEMPORARY(v_clobs(k)) = 1 THENDBMS_LOB.FREETEMPORARY(v_clobs(k));END IF;END LOOP;END LOOP;-- 插入完成后恢复 LOGGING 模式EXECUTE IMMEDIATE 'ALTER TABLE lob_table LOGGING';-- 输出统计信息DBMS_OUTPUT.PUT_LINE('Total rows inserted: ' || p_rows);DBMS_OUTPUT.PUT_LINE('Time taken: ' || TO_CHAR(SYSTIMESTAMP - v_start_time));EXCEPTIONWHEN OTHERS THEN-- 异常处理:尝试释放已创建的临时LOBIF v_clobs IS NOT NULL THENFOR k IN 1..v_clobs.COUNT LOOPIF v_clobs.EXISTS(k) AND DBMS_LOB.ISTEMPORARY(v_clobs(k)) = 1 THENDBMS_LOB.FREETEMPORARY(v_clobs(k));END IF;END LOOP;END IF;-- 回滚事务ROLLBACK;-- 重新抛出异常RAISE;
END;
/select bytes/1024/1024 size_mb from dba_segments where segment_name = upper('lob_table');SIZE_MB
----------.0625
批量插入优化策略:
- 临时LOB:使用
DBMS_LOB.Createtemporary
创建临时LOB对象,减少磁盘I/O - 绑定变量:避免在SQL语句中直接拼接LOB值,使用绑定变量提高效率
- 分批次提交:每1000行提交一次事务,平衡锁表时间和日志管理
- NOLOGGING模式:在批量插入前启用NOLOGGING模式,可提高插入速度约3-5倍
- 并行执行:对于超大规模数据,可考虑使用
PARALLEL
提示并行插入
执行上述存储过程插入10万行数据:
SET SERVEROUTPUT ON;
BEGINinsert_lob_data(100000); -- 插入10万行
END;
/-- 插入数据过程中,表一直在变大
select bytes/1024/1024 size_mb from dba_segments where segment_name = upper('lob_table');SIZE_MB
----------663SQL> /SIZE_MB
----------671
插入性能优化:
对于超大规模数据插入,建议采用以下优化措施:
- 使用
FORALL
批量插入代替循环逐行插入 - 启用
COMMIT
前的NOLOGGING
模式,减少重做日志开销 - 调整
PCTVERSION
参数,减少版本空间占用 - 考虑使用外部表或SQL*Loader进行超大规模数据导入
三、拆分LOB表结构
为提高大型LOB表的查询性能和管理便利性,可采用表空间分离或分区表策略拆分LOB数据。
表空间分离是最简单有效的方式,将LOB数据存储到独立表空间,避免与常规表数据竞争I/O资源。
-- 创建专用表空间用于存储拆分后的LOB数据
CREATE TABLESPACE lob_tbs_split
DATAFILE '/oradata/ora11g/lob_tbs_split01.dbf' SIZE 100M AUTOEXTEND ON MAXSIZE UNLIMITED
LOGGINGExtent Management LocalSegment Space Management Auto;-- 将LOB数据移动到新表空间
ALTER TABLE lob_table MOVE LOB (text_data) STORE AS (TABLESPACE lob_tbs_split);
ALTER TABLE lob_table MOVE LOB (binary_data) STORE AS (TABLESPACE lob_tbs_split);这些命令只是移动了LOB列的存储段(LOB Segment)到 lob_tbs_split 表空间,但并没有移动表本身的数据段(Table Segment)。因此:
表的数据段(存储 id, created_at 等非LOB列)仍然在 USERS 表空间
LOB的数据段(存储 text_data, binary_data 列)已经移动到 lob_tbs_split 表空间set lin 100
col SEGMENT_NAME for a30
col TABLESPACE_NAME for a30
SELECT SEGMENT_NAME,SEGMENT_TYPE,TABLESPACE_NAME
FROM DBA_SEGMENTS
WHERE SEGMENT_NAME IN (SELECT SEGMENT_NAME FROM USER_LOBS WHERE TABLE_NAME = 'LOB_TABLE'
);
SEGMENT_NAME SEGMENT_TYPE TABLESPACE_NAME
------------------------------ ------------------------------------ ------------------------------
SYS_LOB0000112369C00002$$ LOBSEGMENT LOB_TBS_SPLIT
SYS_LOB0000112369C00003$$ LOBSEGMENT LOB_TBS_SPLIT