Oracle에서 MySQL로 변환 - Oracle 스크립트를 사용하는 방법

수요 배경
최근에 Oracle의 데이터베이스를 MySQL로 변환하고 Oracle의 데이터도 MySQL로 이전해야 하는 프로젝트가 있습니다.ORM 프레임워크는 Hibernate를 사용합니다.여러 가지 방법을 시도했다.
Navicat Premium 데이터 전송 기능
전송 실패
DB Convert Studio 주종 복제 기능
기본적으로 성공할 수 있고 문제가 많다.
  • 속도가 매우 느리다.
  • 서로 의존하는 키를 맞춤형으로 처리해야 한다
  • 특수 필드 유형: Oracle의 Number(19)는 MySQL의Decimal 형식으로 변환됩니다. 사실 자바 실체 클래스에서는 Long 유형이고 후속 새로운 실체 클래스는 MySQL에 대응하는 BigInt를 자동으로 생성합니다.Java의 Boolean 유형도 있습니다.

  • DB Convert 사용에 관해서는 블로거의 또 다른 기사를 참고할 수 있다.
    사용자 정의 스크립트 변환
    오랫동안 고생한 후에 스스로 각본을 써서 이 일을 완성하기로 결정했다.Hibernate는 자동으로 실체 클래스에 따라 데이터베이스 테이블 필드/인덱스/외부 키를 업데이트할 수 있기 때문에 자동으로 메인 키를 추가하는 것은 지원되지 않습니다.따라서 스크립트는 테이블의 생성 문구, 메인 키 문구 추가, 데이터 삽입 문구만 생성하면 되며, 자바 프로젝트가 시작되면 Hibernate는 자동으로 키/인덱스 등 정보를 업데이트합니다.자신이 쓴 스크립트는 맞춤형화 정도가 높고 프로젝트의 특징과 결합하여 지속적으로 업데이트할 수 있다.
    DECLARE
        l_user                VARCHAR(255) := 'YOUR_USER_HERE'; --    
        row_data_cur          SYS_REFCURSOR; --     
        l_cur                 NUMBER;
        l_ret                 NUMBER;
        l_col_cnt             NUMBER;
        l_rec_tab             dbms_sql.desc_tab;
        cons_varchar2_code    NUMBER := 1;
        cons_number_code      NUMBER := 2;
        cons_date_code        NUMBER := 12;
        cons_clob_code        NUMBER := 112;
        cons_blob_code        NUMBER := 113;
        cons_timestamp_code   NUMBER := 180;
        l_varchar2_col        VARCHAR2(32767); --1
        l_number_col          NUMBER; --2
        l_date_col            DATE; --12
        l_clob_col            CLOB; --112
        l_blob_col            BLOB; --113
        l_timestamp_col       TIMESTAMP(9); --180
        cons_timestamp_frm    VARCHAR2(32) := 'YYYY-MM-DD HH24:MI:SS';
        CURSOR tabcur IS --  - 
          SELECT table_name,
                 owner,
                 tablespace_name,
                 initial_extent,
                 next_extent,
                 pct_used,
                 pct_free,
                 pct_increase,
                 degree
          FROM   sys.dba_tables
          WHERE  owner = Upper(l_user)
          --              AND table_name IN( 'USER', 'ORG' )
          ;
        --
        colcount              NUMBER(5); --     
        maxcol                NUMBER(5); --     
        fillspace             NUMBER(5); --   (  +  =40)
        collen                NUMBER(5); --       
        pk_column             VARCHAR(255); --    (  )
        pk_column_count       NUMBER(2); --      
        row_count             NUMBER(2); --    
        row_count_sql         VARCHAR(255); --       sql
        insert_into_sql_start VARCHAR(2000); --     sql
        insert_into_sql_full  VARCHAR(32767); --     sql
        select_sql            VARCHAR(2000); --       sql
        col_name_append_quot1 VARCHAR(2000); --     ,  `
        col_name_append_quot2 VARCHAR(2000); --     ,  "
        col_array             dbms_sql.varchar2_table; --   
    --
    BEGIN
        dbms_output.ENABLE(buffer_size => NULL);
    
        maxcol := 0;
    
        --
        FOR tabrec IN tabcur LOOP
            --   
            SELECT Count(column_id)
            INTO   maxcol
            FROM   sys.dba_tab_columns
            WHERE  table_name = tabrec.table_name
                   AND data_type <> 'RAW'
                   AND owner = tabrec.owner;
    
            --
            dbms_output.Put_line('CREATE TABLE '
                                 || tabrec.table_name);
    
            dbms_output.Put_line('( ');
    
            --
            colcount := 0;
    
            row_count := 0;
    
            col_name_append_quot1 := '';
    
            col_name_append_quot2 := '';
    
            insert_into_sql_start := 'insert into '
                                     || tabrec.table_name
                                     || '(';
    
            FOR item IN (SELECT column_name
                                col1,
                                Decode(data_type, 'BLOB', 'longblob   ',
                                                  'CLOB', 'longtext ',
                                                  'DATE', 'datetime ',
                                                  'FLOAT', 'DECIMAL(10, 2) ',
                                                  'TIMESTAMP(6)', 'datetime  ',
                                                  'NVARCHAR2', 'VARCHAR'
                                                               || '('
                                                               || char_length
                                                               || ') ',
                                                  'VARCHAR2', 'VARCHAR'
                                                              || '('
                                                              || char_length
                                                              || ') ',
                                                  'NUMBER', 'DECIMAL'
                                                            ||
                                Decode(Nvl(data_precision, 0), 0, ' ',
                                                               ' ('
                                                               ||
                                data_precision
                                                               ||
                                Decode(Nvl(data_scale, 0), 0, ') ',
                                                           ','
                                                           || data_scale
                                                           || ') ')))
                                            col2
                         FROM   sys.dba_tab_columns
                         WHERE  owner = Upper(l_user)
                                AND table_name = tabrec.table_name
                                AND data_type <> 'RAW'
                         ORDER  BY column_id) LOOP
                collen := Length(item.col1);
    
                fillspace := 40 - collen;
    
                dbms_output.Put('`'
                                || item.col1
                                || '`');
    
                --
                FOR i IN 1 .. fillspace LOOP
                    dbms_output.Put(' ');
                END LOOP;
    
                --            
                IF item.col2 LIKE 'DECIMAL (19) ' THEN --     id
                  dbms_output.Put('bigint ');
                ELSIF item.col2 = 'DECIMAL (1) ' THEN --   bool
                  dbms_output.Put('tinyint ');
                ELSE
                  dbms_output.Put(item.col2);
                END IF;
    
                colcount := colcount + 1;
    
                Col_array(colcount) := item.col1;
    
                --
                IF ( colcount < maxcol ) THEN
                  dbms_output.Put_line(',');
    
                  col_name_append_quot1 := col_name_append_quot1
                                           || '`'
                                           || item.col1
                                           || '`'
                                           || ', ';
    
                  col_name_append_quot2 := col_name_append_quot2
                                           || '"'
                                           || item.col1
                                           || '"'
                                           || ', ';
                ELSE
                  dbms_output.Put_line(') ;');
    
                  col_name_append_quot1 := col_name_append_quot1
                                           || '`'
                                           || item.col1
                                           || '`';
    
                  col_name_append_quot2 := col_name_append_quot2
                                           || '"'
                                           || item.col1
                                           || '"';
                END IF;
            END LOOP;
    
            pk_column_count := 0;
    
            pk_column := '';
    
            SELECT Count(cols.column_name)
            INTO   pk_column_count
            FROM   all_constraints cons,
                   all_cons_columns cols
            WHERE  cons.constraint_type = 'P'
                   AND cols.table_name = tabrec.table_name
                   AND cons.constraint_name = cols.constraint_name
                   AND cons.owner = cols.owner
                   AND cons.owner = tabrec.owner;
    
            IF pk_column_count > 0 THEN
              FOR pk_name IN (SELECT cols.column_name
                              INTO   pk_column
                              FROM   all_constraints cons,
                                     all_cons_columns cols
                              WHERE  cons.constraint_type = 'P'
                                     AND cols.table_name = tabrec.table_name
                                     AND cons.constraint_name = cols.constraint_name
                                     AND cons.owner = cols.owner
                                     AND cons.owner = tabrec.owner) LOOP
                  pk_column := pk_column
                               || pk_name.column_name
                               || ',';
              END LOOP;
            END IF;
    
            IF pk_column_count > 0 THEN
              pk_column := Substr(pk_column, 1, Length(pk_column) - 1);
    
              dbms_output.Put_line('ALTER TABLE '
                                   || tabrec.table_name
                                   || ' ADD CONSTRAINT '
                                   || tabrec.table_name
                                   || '_PK_'
                                   || ' PRIMARY KEY ('
                                   || pk_column
                                   ||');');
            END IF;
    
            select_sql := 'select '
                          || col_name_append_quot2
                          || ' from '
                          || l_user
                          || '.'
                          || tabrec.table_name
                          || '';
    
            --        dbms_output.Put_line(select_sql);
            insert_into_sql_start := insert_into_sql_start
                                     || col_name_append_quot1
                                     || ') values(';
    
            l_cur := dbms_sql.open_cursor;
    
            dbms_sql.Parse(l_cur, select_sql, dbms_sql.native);
    
            dbms_sql.Describe_columns(l_cur, l_col_cnt, l_rec_tab);
    
            FOR i IN 1..l_rec_tab.count LOOP
                IF L_rec_tab(i).col_type = cons_varchar2_code THEN --    
                  dbms_sql.Define_column(l_cur, i, l_varchar2_col,
                  L_rec_tab(i).col_max_len);
                ELSIF L_rec_tab(i).col_type = cons_number_code THEN --    
                  dbms_sql.Define_column(l_cur, i, l_number_col);
                ELSIF L_rec_tab(i).col_type = cons_date_code THEN --date
                  dbms_sql.Define_column(l_cur, i, l_date_col);
                ELSIF L_rec_tab(i).col_type = cons_clob_code THEN --clob
                  dbms_sql.Define_column(l_cur, i, l_clob_col);
                ELSIF L_rec_tab(i).col_type = cons_blob_code THEN --clob
                  dbms_sql.Define_column(l_cur, i, l_blob_col);
                ELSIF L_rec_tab(i).col_type = cons_timestamp_code THEN --timestamp
                  dbms_sql.Define_column(l_cur, i, l_timestamp_col);
                ELSE
                  Raise_application_error(-20001, 'Column: '
                                                  ||L_rec_tab(i).col_name
                                                  ||'Type not supported: '
                                                  ||L_rec_tab(i).col_type);
                END IF;
            END LOOP;
    
            l_ret := dbms_sql.EXECUTE(l_cur);
    
            LOOP
                insert_into_sql_full := insert_into_sql_start;
    
                l_ret := dbms_sql.Fetch_rows(l_cur);
    
                exit WHEN l_ret = 0;
    
                FOR i IN 1..l_rec_tab.count LOOP
                    IF L_rec_tab(i).col_type = cons_varchar2_code THEN
                      --     
                      dbms_sql.Column_value(l_cur, i, l_varchar2_col);
    
                      IF l_varchar2_col IS NULL THEN
                        insert_into_sql_full := insert_into_sql_full
                                                || 'NULL,';
                      ELSE
                        insert_into_sql_full := insert_into_sql_full
                                                || ''''
                                                || Replace(To_char(l_varchar2_col),
                                                   ''''
                                                   ,
                                                   '\''')
                                                || ''','; --     
                      END IF;
                    ELSIF L_rec_tab(i).col_type = cons_number_code THEN
                      --    
                      dbms_sql.Column_value(l_cur, i, l_number_col);
    
                      IF l_number_col IS NULL THEN
                        insert_into_sql_full := insert_into_sql_full
                                                || 'NULL,';
                      ELSE
                        insert_into_sql_full := insert_into_sql_full
                                                || To_char(l_number_col)
                                                || ',';
                      END IF;
                    ELSIF L_rec_tab(i).col_type = cons_date_code THEN --date
                      dbms_sql.Column_value(l_cur, i, l_date_col);
    
                      IF l_date_col IS NULL THEN
                        insert_into_sql_full := insert_into_sql_full
                                                || 'NULL,';
                      ELSE
                        insert_into_sql_full := insert_into_sql_full
                                                || ''''
                                                ||
                        To_char(l_date_col, cons_timestamp_frm)
                                                || ''',';
                      END IF;
                    ELSIF L_rec_tab(i).col_type = cons_clob_code THEN --Clob
                      dbms_sql.Column_value(l_cur, i, l_clob_col);
    
                      IF l_clob_col IS NULL THEN
                        insert_into_sql_full := insert_into_sql_full
                                                || 'NULL,';
                      ELSE
                        --                insert_into_sql_full := insert_into_sql_full || '''' || dbms_lob.substr(l_clob_col) || ''',';
                        insert_into_sql_full := insert_into_sql_full
                                                || ''''
                                                || 'CLOB HERE, SKIP'
                                                || ''',';
                      END IF;
                    ELSIF L_rec_tab(i).col_type = cons_blob_code THEN --Blob
                      dbms_sql.Column_value(l_cur, i, l_blob_col);
    
                      IF l_blob_col IS NULL THEN
                        insert_into_sql_full := insert_into_sql_full
                                                || 'NULL,';
                      ELSE
                        insert_into_sql_full := insert_into_sql_full
                                                || '0x'
                                                || dbms_lob.Substr(l_blob_col)
                                                || ',';
                      END IF;
                    ELSIF L_rec_tab(i).col_type = cons_timestamp_code THEN
                      --timestamp
                      dbms_sql.Column_value(l_cur, i, l_timestamp_col);
    
                      IF l_timestamp_col IS NULL THEN
                        insert_into_sql_full := insert_into_sql_full
                                                || 'NULL,';
                      ELSE
                        insert_into_sql_full := insert_into_sql_full
                                                || ''''
                                                ||
                        To_char(l_timestamp_col, cons_timestamp_frm)
                                                || ''',';
                      END IF;
                    ELSE
                      Raise_application_error(-20001, 'Column: '
                                                      ||L_rec_tab(i).col_name
                                                      ||'Type not supported: '
                                                      ||L_rec_tab(i).col_type);
                    END IF;
                END LOOP;
    
                insert_into_sql_full := Substr(insert_into_sql_full, 1, Length(
                                        insert_into_sql_full) - 1);
                --      ,
    
                insert_into_sql_full := insert_into_sql_full
                                        || ');';
    
                dbms_output.Put_line(insert_into_sql_full);
            END LOOP;
        END LOOP;
    END; 
    

    스크립트 밟기 설명
    내 프로젝트에서 데이터베이스 전환의 수요를 완전히 만족시켰다.다른 항목을 사용하려면 다음과 같은 몇 가지를 주의해야 한다
    지원되는 데이터 유형
    스크립트 239-259 줄, 항목에 나타난 필드 형식만 지원합니다.다음 스크립트를 사용하여 프로젝트 데이터베이스의 모든 유형을 확인할 수 있습니다.
    SELECT
    	DATA_TYPE, DATA_SCALE, COUNT(*) QTY
    FROM
    	sys.dba_tab_columns 
    WHERE
    	owner = UPPER( 'YOUR_USER_HERE' ) 
    	and table_name not in (select view_name from all_views where owner = 'YOUR_USER_HERE')
    	GROUP BY DATA_TYPE,  DATA_SCALE
    ORDER BY DATA_TYPE ASC, QTY DESC;
    

    유형 코드는 Oracle 문서를 참조하십시오.https://docs.oracle.com/cd/E11882_01/server.112/e41085/sqlqr06002.htm#SQLQR959
    스크립트 실행 속도
    스크립트에서 dbms 사용output.Put_line은 생성된 스크립트를 출력합니다. 라이브러리 데이터가 많으면 실행이 매우 느립니다. UTL 을 통해FILE.put_line 방식으로 파일에 출력하면 실행 속도가 훨씬 빨라집니다
    Blob 및 Clob
    Blob 및 Clob 유형은 스크립트 320, 332에서 처리됩니다. Putline은 최대 32767자를 지원합니다. 이 제한을 초과하면 문장 실행이 잘못됩니다.이 문제에 관해서 인터넷에서 정의 함수를 순환 인쇄한다고 언급한 적이 있는데 이것은 시도해 본 적이 없다. 그러나 가능할 것이다. 단지 순환 인쇄는 여분의 줄을 바꿀 수 있지만 실행이 끝난 후에 정규를 통해 여분의 줄을 삭제하면 된다.
    dbms_sql.Describe_columns ORA-06502 예외 사항
    이것은 Oracle 테이블의 필드가 32자를 초과하기 때문에 발생합니다. 구체적으로 제 다른 글을 참고하십시오.https://blog.csdn.net/jiangshanwe/article/details/106530155DBA/Java 개발자와 소통해 이 필드의 길이를 32비트 이내로 줄이면 된다.
    기타 데이터베이스 지원
    SQL Server 또는 다른 데이터베이스로 변환해야 하는 경우 대상 데이터베이스의 구문에 따라 용도를 변경할 수 있습니다.
    참고 자료
    https://stackoverflow.com/questions/937398/how-to-get-oracle-create-table-statement-in-sqlplus https://github.com/teopost/oracle-scripts/blob/master/fn_gen_inserts.sql https://docs.oracle.com/cd/E11882_01/server.112/e41085/sqlqr06002.htm#SQLQR959 https://stackoverflow.com/questions/1649183/generating-sql-insert-into-for-oracle

    좋은 웹페이지 즐겨찾기