Files
article/oracle/oracle-表重定义.md
2025-08-31 16:12:04 +08:00

5.3 KiB

表重定义

DECLARE
    -- 参数定义
    l_orig_table      VARCHAR2(30) := 'T_FOC_CREW_MQ_NEW';
    l_int_table       VARCHAR2(30) := 'T_FOC_CREW_MQ_NEW_TEMP';
    l_orig_owner      VARCHAR2(30) := 'KNDBFOC';
    l_tablespace      VARCHAR2(30) := 'KNDBFOC';

    -- 变量
    l_num_errors      PLS_INTEGER := 0;
    l_start_time      TIMESTAMP;
    l_end_time        TIMESTAMP;

BEGIN
    DBMS_OUTPUT.PUT_LINE('[INFO] 开始在线重定义流程: ' || TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS'));
    l_start_time := SYSTIMESTAMP;

    -- Step 1: 检查是否支持重定义
    DBMS_OUTPUT.PUT_LINE('[INFO] 步骤 1: 检查表是否支持在线重定义...');
    BEGIN
        DBMS_REDEFINITION.CAN_REDEF_TABLE(
            uname        => l_orig_owner,
            tname        => l_orig_table,
            options_flag => DBMS_REDEFINITION.CONS_USE_PK
        );
        DBMS_OUTPUT.PUT_LINE('[SUCCESS] 表支持在线重定义。');
    EXCEPTION
        WHEN OTHERS THEN
            DBMS_OUTPUT.PUT_LINE('[ERROR] 检查失败: ' || SQLERRM);
            RAISE;
    END;

    -- Step 2: 创建中间分区表
    DBMS_OUTPUT.PUT_LINE('[INFO] 步骤 2: 创建中间分区表...');
    BEGIN
        EXECUTE IMMEDIATE '
            CREATE TABLE ' || l_orig_owner || '.' || l_int_table || ' (
                ID          NUMBER(38) NOT NULL,
                MESSAGE_ID  VARCHAR2(255),
                TOPIC       VARCHAR2(255),
                CHANNEL     VARCHAR2(255),
                INSERT_TIME DATE,
                TEXT1       VARCHAR2(2000),
                TEXT2       VARCHAR2(2000 CHAR),
                TEXT3       VARCHAR2(2000 CHAR),
                TEXT4       VARCHAR2(2000 CHAR)
            )
            PARTITION BY RANGE (INSERT_TIME) INTERVAL(NUMTOYMINTERVAL(1, ''MONTH''))
            (
                PARTITION P_INIT VALUES LESS THAN (DATE ''2020-01-01'')
            )
            TABLESPACE ' || l_tablespace;

        DBMS_OUTPUT.PUT_LINE('[SUCCESS] 中间表创建成功。');
    EXCEPTION
        WHEN OTHERS THEN
            IF SQLCODE = -955 THEN
                DBMS_OUTPUT.PUT_LINE('[WARNING] 表已存在,跳过创建。');
            ELSE
                DBMS_OUTPUT.PUT_LINE('[ERROR] 创建失败: ' || SQLERRM);
                RAISE;
            END IF;
    END;

    -- Step 3: 开始重定义
    DBMS_OUTPUT.PUT_LINE('[INFO] 步骤 3: 开始在线重定义...');
    BEGIN
        DBMS_REDEFINITION.START_REDEF_TABLE(
            uname        => l_orig_owner,
            orig_table   => l_orig_table,
            int_table    => l_int_table,
            options_flag => DBMS_REDEFINITION.CONS_USE_PK
        );
        DBMS_OUTPUT.PUT_LINE('[SUCCESS] 重定义已启动。');
    EXCEPTION
        WHEN OTHERS THEN
            DBMS_OUTPUT.PUT_LINE('[ERROR] 启动失败: ' || SQLERRM);
            RAISE;
    END;

    -- Step 4: 复制依赖对象(✅ 极简调用,仅传必要参数)
    DBMS_OUTPUT.PUT_LINE('[INFO] 步骤 4: 复制依赖对象...');
    l_num_errors := 0; -- 重置错误计数
    BEGIN
        DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(
            uname      => l_orig_owner,
            orig_table => l_orig_table,
            int_table  => l_int_table,
            num_errors => l_num_errors
        );

        IF l_num_errors = 0 THEN
            DBMS_OUTPUT.PUT_LINE('[SUCCESS] 依赖对象复制完成。');
        ELSE
            DBMS_OUTPUT.PUT_LINE('[WARNING] 复制完成,但有 ' || l_num_errors || ' 个错误。');
            DBMS_OUTPUT.PUT_LINE('[INFO] 请查询 DBA_REDEFINITION_ERRORS 查看详情。');
        END IF;
    EXCEPTION
        WHEN OTHERS THEN
            DBMS_OUTPUT.PUT_LINE('[ERROR] 复制依赖对象时出错: ' || SQLERRM);
            -- 不中断,继续完成
    END;

    -- Step 5: 同步增量数据
    DBMS_OUTPUT.PUT_LINE('[INFO] 步骤 5: 同步增量数据...');
    BEGIN
        DBMS_REDEFINITION.SYNC_INTERIM_TABLE(
            uname      => l_orig_owner,
            orig_table => l_orig_table,
            int_table  => l_int_table
        );
        DBMS_OUTPUT.PUT_LINE('[SUCCESS] 增量同步完成。');
    EXCEPTION
        WHEN OTHERS THEN
            DBMS_OUTPUT.PUT_LINE('[WARNING] 增量同步失败: ' || SQLERRM);
    END;

    -- Step 6: 完成重定义
    DBMS_OUTPUT.PUT_LINE('[INFO] 步骤 6: 完成重定义...');
    BEGIN
        DBMS_REDEFINITION.FINISH_REDEF_TABLE(
            uname      => l_orig_owner,
            orig_table => l_orig_table,
            int_table  => l_int_table
        );
        DBMS_OUTPUT.PUT_LINE('[SUCCESS] 重定义完成!表已成功转为分区表。');
    EXCEPTION
        WHEN OTHERS THEN
            DBMS_OUTPUT.PUT_LINE('[ERROR] 完成失败: ' || SQLERRM);
            RAISE;
    END;

    l_end_time := SYSTIMESTAMP;
    DBMS_OUTPUT.PUT_LINE('[INFO] 总耗时: ' || TO_CHAR(l_end_time - l_start_time));

    DBMS_OUTPUT.PUT_LINE('[INFO] ✅ 操作成功!');
    DBMS_OUTPUT.PUT_LINE('[INFO] ⚠️  注意:请手动重新授权该表的访问权限。');

EXCEPTION
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('[FATAL] 未预期错误: ' || SQLERRM);
        DBMS_OUTPUT.PUT_LINE('[INFO] 如需中止,请运行:');
        DBMS_OUTPUT.PUT_LINE('BEGIN DBMS_REDEFINITION.ABORT_REDEF_TABLE(''KNDBFOC'', ''T_FOC_CREW_MQ_NEW'', ''T_FOC_CREW_MQ_NEW_TEMP''); END;');
        RAISE;

END;
/
ALTER SYSTEM FLUSH SHARED_POOL;