AWS Schema Conversion Tool を使用した Oracle から Amazon RDS for MySQL または Amazon Aurora MySQL への移行 - AWS Schema Conversion Tool

AWS Schema Conversion Tool を使用した Oracle から Amazon RDS for MySQL または Amazon Aurora MySQL への移行

変換した MySQL コードで Oracle データベース関数をエミュレートするには、AWS SCT で Oracle から MySQL への拡張パックを使用します。拡張機能の詳細については、「AWS Schema Conversion Tool 拡張パックの使用」を参照してください。

MySQL をターゲットデータベースとする場合の権限

ターゲットとして MySQL に必要な権限を以下に示します。

  • CREATE ON *.*

  • ALTER ON *.*

  • DROP ON *.*

  • INDEX ON *.*

  • REFERENCES ON *.*

  • SELECT ON *.*

  • CREATE VIEW ON *.*

  • SHOW VIEW ON *.*

  • TRIGGER ON *.*

  • CREATE ROUTINE ON *.*

  • ALTER ROUTINE ON *.*

  • EXECUTE ON *.*

  • CREATE TEMPORARY TABLES ON *.*

  • AWS_LAMBDA_ACCESS

  • INSERT, UPDATE ON AWS_ORACLE_EXT.*

  • INSERT, UPDATE, DELETE ON AWS_ORACLE_EXT_DATA.*

バージョン 5.7 以前の MySQL データベースをターゲットとして使用する場合は、AWS_LAMBDA_ACCESS の代わりに INVOKE LAMBDA *.* 権限を付与します。MySQL データベースバージョン 8.0 以降の場合は、AWS_LAMBDA_ACCESS 権限を付与します。

次のコード例を使用してデータベースユーザーを作成し、権限を付与できます。

CREATE USER 'user_name' IDENTIFIED BY 'your_password'; GRANT CREATE ON *.* TO 'user_name'; GRANT ALTER ON *.* TO 'user_name'; GRANT DROP ON *.* TO 'user_name'; GRANT INDEX ON *.* TO 'user_name'; GRANT REFERENCES ON *.* TO 'user_name'; GRANT SELECT ON *.* TO 'user_name'; GRANT CREATE VIEW ON *.* TO 'user_name'; GRANT SHOW VIEW ON *.* TO 'user_name'; GRANT TRIGGER ON *.* TO 'user_name'; GRANT CREATE ROUTINE ON *.* TO 'user_name'; GRANT ALTER ROUTINE ON *.* TO 'user_name'; GRANT EXECUTE ON *.* TO 'user_name'; GRANT CREATE TEMPORARY TABLES ON *.* TO 'user_name'; GRANT AWS_LAMBDA_ACCESS TO 'user_name'; GRANT INSERT, UPDATE ON AWS_ORACLE_EXT.* TO 'user_name'; GRANT INSERT, UPDATE, DELETE ON AWS_ORACLE_EXT_DATA.* TO 'user_name';

前述の例では、[user_name] をお客様の設定のユーザー名に置き換えます。your_password を安全なパスワードに置き換えます。

バージョン 5.7 以前の MySQL データベースをターゲットとして使用する場合は、GRANT AWS_LAMBDA_ACCESS TO 'user_name' の代わりに GRANT INVOKE LAMBDA ON *.* TO 'user_name' を使用してください。

Amazon RDS for MySQL または Aurora MySQL をターゲットとして使用するには、lower_case_table_names パラメータを 1 に設定します。この値は、MySQL サーバーがテーブル、インデックス、トリガー、データベースなどのオブジェクト名の識別子を、大文字と小文字を区別せずに処理することを意味します。ターゲットインスタンスでバイナリログを有効にしている場合は、log_bin_trust_function_creators パラメータを 1 と設定します。この場合、ストアド関数を作成するのに、DETERMINISTIC 特性、READS SQL DATA 特性、NO SQL 特性を使用する必要はありません。これらのパラメータを設定するには、新しい DB パラメータグループを作成するか、既存の DB パラメータグループを変更します。

Oracle から MySQL への変換設定

Oracle から MySQL への変換設定を編集するには、AWS SCT で [設定] を選択し、[変換設定] を選択します。上のリストから [Oracle] を選択し、次に [Oracle — MySQL] を選択します。AWS SCT に、Oracle から MySQL への変換に使用可能なすべての設定が表示されます。

AWS SCT の Oracle から MySQL への変換設定には、以下のオプションが含まれています。

  • 変換されたコード内のアクションアイテムに関するコメントの数を制限する。

    [変換後のコードにコメントを追加] で、選択した重要度以上のアクションアイテムについて、アクションアイテムの重要度を選択します。AWS SCT は、選択した重要度以上のアクションアイテムについて、変換後のコードにコメントを追加します。

    たとえば、変換したコード内のコメントの数を最小限に抑えるには、[エラーのみ] を選択します。変換したコードのすべてのアクション項目にコメントを含めるには、[すべてのメッセージ] を選択します。

  • これに対処するため、ソース Oracle ROWID データベースでは疑似列を使用できますが、MySQL は同様の機能をサポートしていません。AWS SCT は変換されたコード内の ROWID 疑似列をエミュレートできます。そのためには、[行 ID を生成しますか] で [ID として生成] を選択します。

    Oracle のソースコードで ROWID 疑似列を使用していない場合は、[行 ID を生成しますか] で [生成しない] を選択します。この場合、変換されたコードの処理が速くなります。

  • MySQL がサポートしていないパラメータを持つTO_CHARTO_DATETO_NUMBER 関数が含まれているソースの Oracle コードを操作する。デフォルトでは、AWS SCT は変換後のコードでこれらのパラメータの使用法をエミュレートします。

    ソース Oracle コードに PostgreSQL がサポートするパラメータのみが含まれている場合は、ネイティブの MySQL TO_CHARTO_DATETO_NUMBER 関数を使用できます。この場合、変換されたコードの処理が速くなります。これらのパラメータのみを含めるには、以下の値を選択します。

    • 関数 TO_CHAR () は Oracle 固有のフォーマット文字列を使用しません

    • 関数 TO_DATE () は Oracle 固有のフォーマット文字列を使用しません

    • 関数 TO_NUMBER () は Oracle 固有のフォーマット文字列を使用しません

  • データベースとアプリケーションが異なるタイムゾーンで実行されているかどうかを調べる。デフォルトでは、AWS SCT は変換されたコードのタイムゾーンをエミュレートします。ただし、データベースとアプリケーションが同じタイムゾーンを使用している場合は、このエミュレーションは必要ありません。この場合、[クライアント側のタイムゾーンをサーバーのタイムゾーンと一致させる] を選択してください。

移行に関する考慮事項

Oracle を RDS for MySQL または Aurora MySQL に変換する場合、ステートメントの実行順序を変更するには、GOTO ステートメントとラベルを使用できます。GOTO ステートメントに続くすべての GOTO ステートメントはスキップされ、ラベルで処理が継続されます。GOTO ステートメントとラベルは、プロシージャ、バッチ、またはステートメント ブロック内のどこでも使用できます。GOTO ステートメントをネストすることもできます。

MySQL は GOTO ステートメントを使用しません。AWS SCT が GOTO ステートメントが含まれるコードを変換する場合、ステートメントは BEGIN…END または LOOP…END LOOP ステートメントを使用するように変換されます。

次の表は、AWS SCT が GOTO ステートメントを変換する方法の一例です。

Oracle ステートメント MySQL ステートメント
BEGIN .... statement1; .... GOTO label1; statement2; .... label1: Statement3; .... END
BEGIN label1: BEGIN .... statement1; .... LEAVE label1; statement2; .... END; Statement3; .... END
BEGIN .... statement1; .... label1: statement2; .... GOTO label1; statement3; .... statement4; .... END
BEGIN .... statement1; .... label1: LOOP statement2; .... ITERATE label1; LEAVE label1; END LOOP; statement3; .... statement4; .... END
BEGIN .... statement1; .... label1: statement2; .... statement3; .... statement4; .... END
BEGIN .... statement1; .... label1: BEGIN statement2; .... statement3; .... statement4; .... END; END

Oracle の WITH ステートメントから RDS for MySQL または Amazon Aurora MySQL への変換

名前 (query_name) をサブクエリのブロックに割り当てるには、WITH 句 (subquery_factoring) を Oracle で使用します。サブクエリブロックをクエリの複数の場所で参照するには、query_name を指定します。サブクエリブロックにリンクまたはパラメータ (ローカル、プロシージャ、関数、パッケージ) が含まれていない場合、AWS SCT はその句をビューまたは一時テーブルに変換します。

句を一時テーブルに変換する利点は、サブクエリへの繰り返し参照がより効率的であることです。各参照によって要求されるのではなく、一時テーブルからデータが簡単に取得されるために効率が向上します。追加のビューまたは一時テーブルを使用して、これをエミュレートできます。ビュー名には <procedure_name>$<subselect_alias> の形式が使用されます。

次の表で例を確認できます。

Oracle ステートメント MySQL ステートメント
CREATE PROCEDURE TEST_ORA_PG.P_WITH_SELECT_VARIABLE_01 (p_state IN NUMBER) AS l_dept_id NUMBER := 1; BEGIN FOR cur IN (WITH dept_empl(id, name, surname, lastname, state, dept_id) AS ( SELECT id, name, surname, lastname, state, dept_id FROM test_ora_pg.dept_employees WHERE state = p_state AND dept_id = l_dept_id) SELECT id,state FROM dept_empl ORDER BY id) LOOP NULL; END LOOP;
CREATE PROCEDURE test_ora_pg.P_WITH_SELECT_VARIABLE_01(IN par_P_STATE DOUBLE) BEGIN DECLARE var_l_dept_id DOUBLE DEFAULT 1; DECLARE var$id VARCHAR (8000); DECLARE var$state VARCHAR (8000); DECLARE done INT DEFAULT FALSE; DECLARE cur CURSOR FOR SELECT ID, STATE FROM (SELECT ID, NAME, SURNAME, LASTNAME, STATE, DEPT_ID FROM TEST_ORA_PG.DEPT_EMPLOYEES WHERE STATE = par_p_state AND DEPT_ID = var_l_dept_id) AS dept_empl ORDER BY ID; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done := TRUE; OPEN cur; read_label: LOOP FETCH cur INTO var$id, var$state; IF done THEN LEAVE read_label; END IF; BEGIN END; END LOOP; CLOSE cur; END;
CREATE PROCEDURE TEST_ORA_PG.P_WITH_SELECT_REGULAR_MULT_01 AS BEGIN FOR cur IN ( WITH dept_empl AS ( SELECT id, name, surname, lastname, state, dept_id FROM test_ora_pg.dept_employees WHERE state = 1), dept AS (SELECT id deptid, parent_id, name deptname FROM test_ora_pg.department ) SELECT dept_empl.*,dept.* FROM dept_empl, dept WHERE dept_empl.dept_id = dept.deptid ) LOOP NULL; END LOOP;
CREATE VIEW TEST_ORA_PG.`P_WITH_SELECT_REGULAR_MULT_01$dept_empl `(id, name, surname, lastname, state, dept_id) AS (SELECT id, name, surname, lastname, state, dept_id FROM test_ora_pg.dept_employees WHERE state = 1); CREATE VIEW TEST_ORA_PG.`P_WITH_SELECT_REGULAR_MULT_01$dept `(deptid, parent_id,deptname) AS (SELECT id deptid, parent_id, name deptname FROM test_ora_pg.department); CREATE PROCEDURE test_ora_pg.P_WITH_SELECT_REGULAR_MULT_01() BEGIN DECLARE var$ID DOUBLE; DECLARE var$NAME VARCHAR (30); DECLARE var$SURNAME VARCHAR (30); DECLARE var$LASTNAME VARCHAR (30); DECLARE var$STATE DOUBLE; DECLARE var$DEPT_ID DOUBLE; DECLARE var$deptid DOUBLE; DECLARE var$PARENT_ID DOUBLE; DECLARE var$deptname VARCHAR (200); DECLARE done INT DEFAULT FALSE; DECLARE cur CURSOR FOR SELECT dept_empl.*, dept.* FROM TEST_ORA_PG.`P_WITH_SELECT_REGULAR_MULT_01$dept_empl ` AS dept_empl, TEST_ORA_PG.`P_WITH_SELECT_REGULAR_MULT_01$dept ` AS dept WHERE dept_empl.DEPT_ID = dept.DEPTID; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done := TRUE; OPEN cur; read_label: LOOP FETCH cur INTO var$ID, var$NAME, var$SURNAME, var$LASTNAME, var$STATE, var$DEPT_ID, var$deptid, var$PARENT_ID, var$deptname; IF done THEN LEAVE read_label; END IF; BEGIN END; END LOOP; CLOSE cur; END; call test_ora_pg.P_WITH_SELECT_REGULAR_MULT_01()
CREATE PROCEDURE TEST_ORA_PG.P_WITH_SELECT_VAR_CROSS_02(p_state IN NUMBER) AS l_dept_id NUMBER := 10; BEGIN FOR cur IN ( WITH emp AS (SELECT id, name, surname, lastname, state, dept_id FROM test_ora_pg.dept_employees WHERE dept_id > 10 ), active_emp AS ( SELECT id FROM emp WHERE emp.state = p_state ) SELECT * FROM active_emp ) LOOP NULL; END LOOP; END;
CREATE VIEW TEST_ORA_PG.`P_WITH_SELECT_VAR_CROSS_01$emp `(id, name, surname, lastname, state, dept_id) AS (SELECT id, name, surname, lastname, state, dept_id FROM TEST_ORA_PG.DEPT_EMPLOYEES WHERE DEPT_ID > 10); CREATE PROCEDURE test_ora_pg.P_WITH_SELECT_VAR_CROSS_02(IN par_P_STATE DOUBLE) BEGIN DECLARE var_l_dept_id DOUBLE DEFAULT 10; DECLARE var$ID DOUBLE; DECLARE done INT DEFAULT FALSE; DECLARE cur CURSOR FOR SELECT * FROM (SELECT ID FROM TEST_ORA_PG. `P_WITH_SELECT_VAR_CROSS_01$emp` AS emp WHERE emp.STATE = par_p_state) AS active_emp; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done := TRUE; OPEN cur; read_label: LOOP FETCH cur INTO var$ID; IF done THEN LEAVE read_label; END IF; BEGIN END; END LOOP; CLOSE cur; END;