Oracle Database から Databricks へ Azure Data Factory  のメタデータ駆動のコピーアクティビティによる多数のテーブルのデータ移行手順

## 概要

Oracle Database から Databricks へ Azure Data Factory (ADF) のメタデータ駆動のコピーアクティビティによる多数のテーブルのデータ移行手順を共有します。オンプレミスにある Oracle Database からデータを移行する場合などに本手順の方法が有効です。メタデータ駆動のコピーアクティビティでは増分連携を実施できることから、データ移行だけでなく、日々のデータ連携にも利用できる便利な機能です。


メタデータ駆動のコピーアクティビティとは、Azure SQL Database のテーブルにデータ連携に必要な設定値を保持させて、自動で生成される３つのテンプレートパイプラインで実行することで、多数のテーブルを連携できる機能です。ADF のコピーアクティビティを利用するパイプラインであることから、コピーアクティビティで利用できる多くのデータストアからの連携が実施できます。

- [データのコピー ツールでメタデータ駆動型の方法を使用して大規模なデータ コピー パイプラインを作成する - Azure Data Factory | Microsoft Learn](https://learn.microsoft.com/ja-jp/azure/data-factory/copy-data-tool-metadata-driven)

本手順ではターゲットとして、 Azure Databricks Delta Lake コネクタを利用しております。ソースが RDB であることから、ステージング設定が必要となります。

- [Azure Databricks Delta Lake との間でデータをコピーする - Azure Data Factory & Azure Synapse | Microsoft Learn](https://learn.microsoft.com/ja-jp/azure/data-factory/connector-azure-databricks-delta-lake?tabs=data-factory)

## 事前準備

次の事項を事前に実施する必要があります。本手順では詳細は省略します。

- リソースの作成
    - Azure でのリソース作成
        - Azure Data Factory の構築
        - Azure SQL Database のデータベースの構築
        - Databricks の構築
        - Azure Storage（ステージング用）の構築
    - ローカル環境でのリソース作成
        - セルフホステッド統合ランタイムの構築
        - Oracle Database の構築
- 認証認可関連の実行
    - セルフホステッド統合ランタイムを ADF に登録
    - Azure SQL Database への ADF のマネージド ID 登録
    - Databricks への ADF のマネージド ID 登録
    - Databricks にて Azure Storage へのアカウントキーを設定 *1
- データベース作成
    - Oracle 上に HR スキーマのテーブルを作成
    - Databricks 上に HR スキーマのテーブルを作成
- ADF にてリンクドサービスの作成
    - Databricks のリンクドサービスを作成
    - Azure SQL Database のリンクドサービスを作成
    - Oracle Database のリンクドサービスを作成

*1 利用するストレージの種類によって Config のキーが異なることに注意が必要である。

Azure Blob Storage の場合には、以下を設定

```text
fs.azure.account.key.<storage-account-name>.blob.core.windows.net
```

Azure Data Lake Storage Gen2  の場合には、以下を設定。

```text
fs.azure.account.key.<storage-account>.dfs.core.windows.net
```


## 実行手順

### 1. ADF の 作成者タブにて`+` -> `データコピーツール`を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/45a91a95-184d-d651-15c5-b7042ed8aed6.png)


### 2. `メタデータ関連のコピータスク`を選択後、Azure SQL Database のリンクドサービスを選び`次へ`をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/85d6d3e2-ed39-a8d9-5fe1-9b91639852c1.png)

### 3.  `接続`にて Oracle Database のリンクドサービスを選択後、データを移行するテーブル（`HR スキーマのテーブル`）をチェックして`次へ`を選択

特定のスキーマ(`HR`)のすべてのテーブルを選択する場合には、スキーマ名とトッド(`HR.`)により検索を行い`すべて選択`を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/fb8cace0-de07-ebf8-faa9-51f7c8bdad31.png)

### 4. `テーブルごとに個別に構成する`をチェックして必要な設定を実施して`次へ`を選択

本手順では設定値の変更を実施していません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/3fb2a84a-19af-8445-12d0-2acda9b95139.png)

### 5.  `接続`にて Databricks Delta のリンクドサービスを選択後、テーブルのマッピングを確認して`次へ`を選択

マッピングが同名のテーブルに対して自動で実施されるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/04cec24d-ee08-5f08-a6c3-4c0b5c657874.png)

### 6. カラムのマッピングを確認して`次へ`を選択

マッピングが同名のカラムに対して自動で実施されるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/27f12e7a-5668-0a7f-5944-3f8e941a3657.png)

### 7. ステージングの設定後、`次へ`を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/df388203-a456-ca1f-5e72-0a0e6dbd5947.png)

### 8. `次へ`を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/7e8b801c-609d-7088-2730-0c89ea1012f6.png)

### 9. `SQL スクリプトのダウンロード`を選択して SQL ファイルをダウンロード後、`パイプラインの表示とパイプライン実行のデバック`をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/f3f5100c-2ec0-8f29-e71a-7bb0ae7690fa.png)

### 10. Azure SQL Database にてダウンロードした SQL を実行

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/c6099988-256e-bc2e-35af-5be1a1f80351.png)

### 11. ADF にて生成されたパイプライン（例：`MetadataDrivenCopyTask_pcl_TopLevel`）をデバック実行後、正常終了することを確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/ba040bd5-21ea-70e1-9dec-3edcd7d489f4.png)

### 12. Databricks にてデータが連携されていることを確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/83b417f3-8cda-3b26-871f-b9524e3b46a1.png)

## その他の検討事項

### 検討事項概要

1. `差分読み込み`に変更
2. ROWID 例や監査列の付与
3. パーティション分割による並列処理の実施
4. カラムマッピングの省略
5. テーブル読み込みの優先順位の設定
6. コピーアクティビティの並列処理数の設定
7. ステージング環境のライフサイクル管理の設定

### 1. `差分読み込み`に変更

データ連携を一度で完了できない場合には、`差分読み込み`の利用を検討してください。本記事の手順 4 にて、`差分読み込み`をチェックすることで日付列などに基づき増分連携が実施できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/0f1e8840-dc01-3283-4b0d-8dbd97b6449e.png)

### 2. ROWID 例や監査列の付与

ROWID （データ移行後は ROWID の値を UUID で設定する想定）や監査列を付与する場合には本記事の手順 4 にてクエリを記述することで容易に実施できます。

```sql
SELECT
    REGEXP_REPLACE(SYS_GUID(), '(.{8})(.{4})(.{4})(.{4})(.{12})', '\1-\2-\3-\4-\5') AS "ROWID"
    ,'OracleDB@//localhost:1521/ORCLPDB1' AS datasource
    ,sysdate AS ingest_date
    ,src.*
from
    "HR"."COUNTRIES" src
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/c96f6fee-c7ad-06a8-f00a-2f3ae745cf29.png)

### 3. パーティション分割による並列処理の実施

次のドキュメントを参考に並列処理の実施することを検討してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/976c44b3-8813-728a-a019-9386dab36ef3.png)

引用元：[Oracle をコピー先またはコピー元としてデータをコピーする - Azure Data Factory & Azure Synapse | Microsoft Learn](https://learn.microsoft.com/ja-jp/azure/data-factory/connector-oracle?tabs=data-factory#parallel-copy-from-oracle)

### 4. カラムマッピングの省略

ソースとターゲットのカラム名が同一である場合には、カラムマッピングを省略できます。省略する場合には、本記事の手順 5 にて`すべてのテーブルの列マッピングをスキップする`をチェックしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/75d4c071-f1c7-3cb5-290f-9d9a1918f801.png)

### 5. テーブル読み込みの優先順位の設定

Azure SQL Database のコントロールテーブルの`TaskId`にて同時実行するパイプラインを制御できるため、大規模なテーブルから連携する場合には優先順位を設定することを検討してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/208998e9-8630-614e-0c55-cd773e31b763.png)

引用元：[データのコピー ツールでメタデータ駆動型の方法を使用して大規模なデータ コピー パイプラインを作成する - Azure Data Factory | Microsoft Learn](https://learn.microsoft.com/ja-jp/azure/data-factory/copy-data-tool-metadata-driven#main-control-table)

### 6. コピーアクティビティの並列処理数の設定

`MaxNumberOfConcurrentTasks`パラメータにて同時に実行するパイプラインの個数を最適な処理時間となるように検討してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/20101465-617a-5c77-0dd4-388ea7425085.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/12acd722-2589-59ab-c4b5-15c27d59991d.png)

引用元：https://learn.microsoft.com/ja-jp/azure/data-factory/copy-data-tool-metadata-driven#parameters

### 7. ステージング環境のライフサイクル管理の設定

ステージングのストレージにてデータが削除されない事象を確認したたため、Azure Storage のデータライフサイクルの設定を検討してください。

- [データ ライフサイクルを自動管理してコストを最適化する - Azure Storage | Microsoft Learn](https://learn.microsoft.com/ja-jp/azure/storage/blobs/lifecycle-management-overview)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/b15ff19b-ccf6-db0c-30ef-031c5e59f942.png)



## 補足

### Azure SQL Database のコントロールテーブルの json のサンプル値

```json
{
	"SourceObjectSettings": {
		"schema": "HR",
		"table": "COUNTRIES"
	},
	"SinkObjectSettings": {
		"database": "hr",
		"table": "countries"
	},
	"CopySourceSettings": {
		"partitionLowerBound": null,
		"partitionUpperBound": null,
		"partitionColumnName": null,
		"partitionNames": null
	},
	"CopySinkSettings": {
		"importSettings": {
			"type": "AzureDatabricksDeltaLakeImportCommand"
		}
	},
	"CopyActivitySettings": {
		"translator": null
	},
	"TopLevelPipelineName": "MetadataDrivenCopyTask_v50_TopLevel",
	"TriggerName": [
		"Sandbox",
		"Manual"
	],
	"DataLoadingBehaviorSettings": {
		"dataLoadingBehavior": "FullLoad"
	},
	"TaskId": 0,
	"CopyEnabled": 1
}
```


### Databricks での HR スキーマのテーブル定義

```sql
%sql
-- DROP SCHEMA HR CASCADE;
create schema HR

CREATE OR REPLACE TABLE HR.COUNTRIES (
  COUNTRY_ID STRING,
  COUNTRY_NAME STRING,
  REGION_ID DECIMAL(28, 10)
)
USING DELTA;

CREATE TABLE HR.DEPARTMENTS (
  DEPARTMENT_ID DECIMAL(4, 0),
  DEPARTMENT_NAME STRING,
  MANAGER_ID DECIMAL(6, 0),
  LOCATION_ID DECIMAL(4, 0)
)
USING DELTA;

CREATE OR REPLACE TABLE HR.EMPLOYEES (
  EMPLOYEE_ID DECIMAL(6, 0),
  FIRST_NAME STRING,
  LAST_NAME STRING,
  EMAIL STRING,
  PHONE_NUMBER STRING,
  HIRE_DATE TIMESTAMP,
  JOB_ID STRING,
  SALARY DECIMAL(8, 2),
  COMMISSION_PCT DECIMAL(2, 2),
  MANAGER_ID DECIMAL(6, 0),
  DEPARTMENT_ID DECIMAL(4, 0)
)
USING DELTA;

CREATE TABLE HR.JOB_HISTORY (
  EMPLOYEE_ID DECIMAL(6, 0),
  START_DATE TIMESTAMP,
  END_DATE TIMESTAMP,
  JOB_ID STRING,
  DEPARTMENT_ID DECIMAL(4, 0)
)
USING DELTA;

CREATE TABLE HR.JOBS (
  JOB_ID STRING,
  JOB_TITLE STRING,
  MIN_SALARY DECIMAL(6, 0),
  MAX_SALARY DECIMAL(6, 0)
)
USING DELTA;

CREATE TABLE HR.LOCATIONS (
  LOCATION_ID DECIMAL(4, 0),
  STREET_ADDRESS STRING,
  POSTAL_CODE STRING,
  CITY STRING,
  STATE_PROVINCE STRING,
  COUNTRY_ID STRING
)
USING DELTA;

CREATE TABLE HR.REGIONS (
  REGION_ID DECIMAL(28, 10),
  REGION_NAME STRING
)
USING DELTA;
```