Oracle LOB使用入门和简单使用,提供学习用的测试用例!

Oracle LOB字段使用方法与数据泵迁移实战指南

Oracle数据库中的LOB(Large Object)字段是存储大型非结构化数据的理想选择,支持高达4GB的文本、图像、音频、视频等数据存储。本问简单介绍创建含LOB/CLOB字段的表结构、批量插入10万行数据、拆分LOB表结构,并提供验证数据完整性的测试用例,适合复习或者学习新知识点用。

一、创建含LOB/CLOB字段的表结构

创建含LOB字段的表时,应根据业务需求选择适当的LOB类型,并合理配置存储参数以优化性能。对于大型文本数据,CLOB是最常用的选择;对于二进制数据,BLOB更为合适。以下是创建含CLOB字段的表的示例,采用SecureFiles存储方式并优化存储参数:

sql 复制代码
-- 创建专用表空间用于存储LOB数据
sqlplus / as sysdba
CREATE TABLESPACE lob_tbs
DATAFILE '/oradata/ora11g/lob_tbs01.dbf' SIZE 100M AUTOEXTEND ON MAXSIZE UNLIMITED
LOGGING
 Extent Management Local
 Segment 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_tbs
    ENABLE STORAGE IN ROW
    CHUNK 8192
    PCTVERSION 5
    COMPRESS HIGH
    DEDUPLICATE
    NOCACHE
    LOGGING
)
LOB (binary_data) STORE AS SECUREFILE (
    TABLESPACE lob_tbs
    ENABLE STORAGE IN ROW
    CHUNK 8192
    PCTVERSION 5
    COMPRESS HIGH
    DEDUPLICATE
    NOCACHE
    LOGGING
);

关键参数解析

  1. SecureFiles:Oracle 11g引入的新存储方式,相比BasicFile提供了更好的性能和更多高级功能
  2. TABLESPACE lob_tbs:将LOB数据单独存储到专用表空间,避免与常规表数据竞争I/O资源
  3. ENABLE STORAGE IN ROW:允许小于4KB的LOB值存储在行内,提升小数据访问效率
  4. CHUNK 8192:设置为8KB(与数据库块大小一致),避免存储碎片
  5. PCTVERSION 5:将版本空间比例从默认10%降至5%,减少空间浪费
  6. COMPRESS HIGH:启用高级压缩,可节省约40-60%的存储空间
  7. DEDUPLICATE:启用去重功能,自动检测并合并重复数据,进一步节省存储空间
  8. NOCACHE:对于只读或低频更新的LOB数据,禁用缓存可减少内存占用
  9. LOGGING:启用日志记录,确保数据完整性和可恢复性

二、批量插入10万行测试数据

对于大型LOB数据的批量插入,直接逐行插入效率低下,应采用PL/SQL批量操作方法,结合临时LOB和分批次提交机制,以提高插入效率。

sql 复制代码
-- 创建存储过程,批量插入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 执行 DDL
    EXECUTE 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) LOOP
        v_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;

            -- 设置ID
            v_ids(v_ids.LAST) := i;

            -- 创建并填充临时CLOB
            DBMS_LOB.CREATETEMPORARY(v_clobs(v_clobs.LAST), TRUE);

            DECLARE
                v_written NUMBER := 0;
                v_chunk   NUMBER := 32767;
                v_to_write NUMBER;
                v_current_buffer VARCHAR2(32767);
            BEGIN
                WHILE v_written < v_max_length LOOP
                    v_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_ids
            INSERT 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 LOOP
            IF DBMS_LOB.ISTEMPORARY(v_clobs(k)) = 1 THEN
                DBMS_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));

EXCEPTION
    WHEN OTHERS THEN
        -- 异常处理:尝试释放已创建的临时LOB
        IF v_clobs IS NOT NULL THEN
            FOR k IN 1..v_clobs.COUNT LOOP
                IF v_clobs.EXISTS(k) AND DBMS_LOB.ISTEMPORARY(v_clobs(k)) = 1 THEN
                    DBMS_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

批量插入优化策略

  1. 临时LOB :使用DBMS_LOB.Createtemporary创建临时LOB对象,减少磁盘I/O
  2. 绑定变量:避免在SQL语句中直接拼接LOB值,使用绑定变量提高效率
  3. 分批次提交:每1000行提交一次事务,平衡锁表时间和日志管理
  4. NOLOGGING模式:在批量插入前启用NOLOGGING模式,可提高插入速度约3-5倍
  5. 并行执行 :对于超大规模数据,可考虑使用PARALLEL提示并行插入

执行上述存储过程插入10万行数据:

sql 复制代码
SET SERVEROUTPUT ON;
BEGIN
    insert_lob_data(100000); -- 插入10万行
END;
/

-- 插入数据过程中,表一直在变大
select bytes/1024/1024 size_mb from dba_segments where segment_name = upper('lob_table');
   SIZE_MB
----------
       663

SQL> /

   SIZE_MB
----------
       671

插入性能优化

对于超大规模数据插入,建议采用以下优化措施:

  • 使用FORALL批量插入代替循环逐行插入
  • 启用COMMIT前的NOLOGGING模式,减少重做日志开销
  • 调整PCTVERSION参数,减少版本空间占用
  • 考虑使用外部表或SQL*Loader进行超大规模数据导入

三、拆分LOB表结构

为提高大型LOB表的查询性能和管理便利性,可采用表空间分离或分区表策略拆分LOB数据。
表空间分离是最简单有效的方式,将LOB数据存储到独立表空间,避免与常规表数据竞争I/O资源。

sql 复制代码
-- 创建专用表空间用于存储拆分后的LOB数据
CREATE TABLESPACE lob_tbs_split
DATAFILE '/oradata/ora11g/lob_tbs_split01.dbf' SIZE 100M AUTOEXTEND ON MAXSIZE UNLIMITED
LOGGING
 Extent Management Local
 Segment 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
相关推荐
武子康3 小时前
Java-144 深入浅出 MongoDB BSON详解:MongoDB核心存储格式与JSON的区别与应用场景
java·开发语言·数据库·mongodb·性能优化·json·bjson
爱喝水的鱼丶3 小时前
SAP-ABAP:SAP中的用户确认对话框:深入理解与实践POPUP_TO_CONFIRM
运维·开发语言·学习·sap·abap
Raymond运维3 小时前
MySQL包安装 -- SUSE系列(SUSE资源库安装MySQL)
linux·运维·数据库·mysql
高山上有一只小老虎3 小时前
如何在DBeaver中配置高斯数据库的连接
数据库
云飞云共享云桌面3 小时前
东莞精密机械制造工厂如何10个SolidWorks共用一台服务器资源
java·运维·服务器·网络·数据库·电脑·制造
lingggggaaaa3 小时前
小迪安全学习笔记(一百零二讲)—— 漏扫项目篇&PoC开发&Yaml语法&插件一键生成&匹配结果&交互提取
笔记·学习·安全·网络安全·交互
ActionTech3 小时前
2025 年 9 月《大模型 SQL 能力排行榜》发布,新增 Kimi K2 最新版测评!
数据库·sql·ai·oracle
里昆3 小时前
【COMSOL】结构力学仿真(压缩弹性体)案例心得
学习
lang201509284 小时前
掌握MyBatis Java API:高效操作数据库
java·数据库·mybatis