Fivetranで(RDS)PostgreSQLから(AWS)Databricksへデータを同期してみた - ③自動同期（増分同期） 編

Fivetranは、様々なデータソース（各種SaaSアプリやDBなど）から、クラウド型DWHを中心としたデータ分析基盤へ、データ同期を自動化させることができるツールです。

最短5分のセットアップでデータパイプラインを構築することができ、それ以降のデータ同期を自動で実行してくれるとのこと。

今回は、このFivetranを使用して(RDS)PostgreSQLから(AWS)Databricksへのパイプラインを構築し、データ同期を行ってみました。

# 全体の流れ
1. <a href="https://qiita.com/ny94/items/bd12a3748f0525b31e08">同期先((AWS)Databricks)を登録します</a>
2. <a href="https://qiita.com/ny94/items/103f6fb892afc5bdf58d">データソース((RDS)PostgreSQL)のコネクターを作成します</a>
3. データの自動同期（増分同期）を確認します　※この記事です

# データの自動同期を確認します
ソース側のデータベースに変更を加えて、自動同期（増分同期）される様子を見ていきたいと思います。

検証をスムーズにするため同期間隔をデフォルトの6時間から15分に変更しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/0727736a-dc88-cf2d-ed91-c4a87e80a0c0.png)

## 1. データ追加
追加されたデータは自動同期にて反映されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/35d0cca4-f289-52ba-e787-6adeb52aec9f.png)
　　↓　自動同期（増分同期）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/14577338-9001-6869-8ef8-c79242209e1a.png)
　　↓　完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/a53c4c95-8d75-df65-5b17-942c2974e0b2.png)
　　↓　結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/8750333d-1460-6011-70b9-4651068d533c.png)
データ追加が反映されていることを確認しました。
また、追加分以外のレコードで「_fivetran_synced」カラムが変わっていないことから、増分同期はちゃんと必要な分のみ同期してくれることを確認。
もしこれが毎回全レコード作り直しとかになっていたら、支払料金が変わってきてしまいます。

## 2. データ更新
データ更新も自動同期で反映されますが、主キー無しテーブルについては以下の問題が発生しました。

:::note warn
**更新できないエラー**
* レプリカアイデンティティを設定しないとデータの更新ができない
* 主キーありテーブルと異なる形で反映される
:::

↓ まず、主キー無しテーブルに更新をかけようとするとエラーになってしまいました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/08ba8115-843d-0269-0eec-ded8c203dd15.png)
↓ 主キーありテーブルは問題なし。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/bf309202-09e1-5b9a-b9ac-88ba49aa5b25.png)


**■ 更新できないエラー について**

論理レプリケーション設定による影響でした。
https://www.postgresql.jp/document/14/html/logical-replication-publication.html

* パブリケーションに指定したテーブルは、「レプリカアイデンティティ」の設定をしなければ、その後UPDATE、DELETEの操作ができなくなってしまう
* 主キーがあればそれがデフォルトでレプリカアイデンティティになるが、
主キーが無い場合はレプリカアイデンティティが設定されないため、追加でレプリカアイデンティティを設定しないとエラーになってしまう
* 追加で設定する設定する際には、下記のいずれかを選択する
    * ユニークキー：一意であり、かつ「NOT NULL」が指定されたカラムでなければならない（それがあればそもそも主キーになっていそう…）
    * full：行全体をキーとするので、主キー/ユニークキーが無いテーブルでも使用できるが、上記ドキュメントによれば『非常に非効率なので、他の解決方法がない場合のみの代替手段』とのこと

今回は検証なので full の方で追加の設定をすることにしますが、非常に非効率だそうなので、もし現実に主キー無しのテーブルを同期する場合があれば、注意が必要そうです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/ebbdf398-cb0b-f503-4342-35b6fdfd0138.png" width=60%>

改めてデータ更新を行い、無事準備完了しました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/d858a0e4-cfca-b6f4-8b45-92a3dd2ebbf8.png" width=60%>

　　↓　自動同期後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/033632ba-0e63-2e5a-0dee-303d3dfd71f4.png)
主キーありテーブルについては想定通り、データ更新が反映されていることを確認しました。

**■ 主キーありテーブルと異なる形で反映される について**

主キー無しテーブルもは反映されていますが、主キーありテーブルとは異なる形をとっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/bd41d77d-25ae-4e78-1204-50fc445b1f4b.png)
主キー無しテーブルの方は、『古い方のレコードが論理削除＋更新後のレコードが新規追加』という形での反映となりました。

やはり、もし現実に主キー無しのテーブルを同期する必要がある場合は注意が必要…

## 3. データ削除
物理削除ではなく、「_fivetran_deleted」カラムの論理削除で反映されます。
データ更新と同様、主キー無しテーブルではレプリカアイデンティティの設定が無いとDELETEがエラーになりますが、設定してあれば同期自体は問題なく反映されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/53e467a6-4530-300a-5067-e52a6125a854.png)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/4615493e-7dec-9263-a68d-8b20777f54ca.png" width=60%>

:::note warn
既に レプリカアイデンティティを full で設定しているため、DELETEできています
:::

　　↓　自動同期後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/58c0ada9-ba9f-1a16-31b3-03c6995bfb4d.png)
「_fivetran_deleted」カラムの論理削除で反映されています。
まず主キーありテーブルについて、想定通りの反映を確認…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/a8f268ef-e72a-6c14-5b84-219f8e2c5a87.png)
主キー無しテーブルについても、同じように反映されることを確認できました。

## 4. カラム追加
カラム追加はそれのみでは反映されませんが、レコードに変更が入ると一緒に反映されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/6864b1f2-ea6d-9162-ef28-4b71413633cf.png)
　　↓　自動同期後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/2c20cc1f-c733-0b61-2993-7ba9580a96cb.png)
カラム追加だけでは反映されない。

　　↓

レコードに変更を入れる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/c51c9952-25b2-a003-dfe7-947d57c973f4.png)
　　↓　自動同期後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/d5de710e-ad7d-2ea5-7e8b-dbe367f6691e.png)
反映されました（追加したカラムはnullでもOK）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/1b72e857-75a0-0464-e500-cec7ef2409d2.png)
もちろん値が入っていてもOKです。

## 5. カラム変更
カラム変更はそれのみでは反映されませんが、レコードに変更が入ると一緒に反映されます。
ただし、拡張方向のカラム変更のみ反映対象なので、反映されないパターンもありました。
#### 数値型 → 文字列型 の変更
変更前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/42540bbe-cd15-a5bb-a347-a248ffc5db1e.png)
文字列型へとカラム変更します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/193ecf1a-b6cd-ab8d-7089-96663e2d6410.png" width=80%>
　　↓　自動同期後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/42540bbe-cd15-a5bb-a347-a248ffc5db1e.png)
これだけでは反映されない。

　　↓

レコードに変更を入れます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/a1feab91-3b54-6e86-1975-1c8fa90dd5bf.png" width=80%>
　　↓　自動同期後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/a4807c45-8c45-bcfe-b591-6bbb16e5ac6e.png)
数値型 → 文字列型 の変更が反映されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/7f44616b-e0e6-3a8e-4e44-6be5a08bc5e2.png)

#### 文字列型 → 数値型 の変更
変更前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/d5892660-5549-df9c-69a9-35eed8093666.png)
数値型へとカラム変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/734fb77a-c5f7-73e6-3926-a0464f6e5f9e.png)　　↓
レコードに変更を入れます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/29e2ca6b-b620-de12-0dc8-1aa6e8f7bb24.png" width=80%>
　　↓　自動同期後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/887b4718-d4b3-c8f2-0e50-2ba4dff5b7c5.png)
文字列型 → 数値型 の変更は同期されません。

## 6. カラム削除
自動同期では反映されませんが、手動で履歴データの再同期というものを行うと、登録されていたデータがnullに更新されるという形で反映されました。
カラム自体は残ったままとなりました。

変更前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/f4493376-c673-fcb8-88fb-98d1c4687ecb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/957a67e3-c2bf-5f74-db18-23c92330857c.png)

カラム削除します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/981d1f34-dd4f-1267-a8c7-fc1325a9456b.png" width=90%>
　　↓　自動同期後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/6ecc085d-36cd-75c9-7e1f-a8adbd7f21ea.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/0628e86f-ac12-e583-f122-bf083c9ed460.png)
反映されない。

　　↓

レコードにも変更を入れてみます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/527cd0b7-a118-b04c-f02e-cf32bd6eccda.png" width=90%>
　　↓　自動同期後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/6ecc085d-36cd-75c9-7e1f-a8adbd7f21ea.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/0628e86f-ac12-e583-f122-bf083c9ed460.png)
反映されない。

　　↓

画面から『すべての履歴データを再同期する』を実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/6c006469-0bb3-81d0-741e-ed2455c10279.png)
　　↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/ee647b90-052b-50ef-330d-1c63be88c63b.png)
　　↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/390d15a7-dfed-f208-ef26-0f9d927d4acb.png)
　　↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/a4807c45-8c45-bcfe-b591-6bbb16e5ac6e.png)
カラム自体は削除されないが、データがnullに更新される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/f07d07a9-99ad-af4c-2489-1e4c335b09c5.png)

## 7. テーブルの追加
テーブルを作成してパブリケーションに追加すると、自動同期にて反映されます。

下記のテーブルを新規に作成します
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/edb837cf-0e03-8ec9-bf3a-100213f1f6a5.png" width=60%>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/49b2828f-e4b3-1a24-0686-ddcf760e48a0.png)
　　↓　自動同期後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/bf40824d-1441-539b-433c-1b63f2f40f92.png)
初期レコードあり／無しパターンどちらも反映されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/3f2f6922-4514-5991-f43f-724bb793f3b0.png)

## 8. テーブルの削除
テーブルの削除は同期されません。

下記のテーブルを削除して見ていきます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/77cf9ba6-5d2e-10cb-c172-b2e7793921ac.png" width=60%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/9d15d93b-2423-6898-7fea-5e6689b1dae3.png" width=60%>

　　↓　自動同期後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/bf40824d-1441-539b-433c-1b63f2f40f92.png)
削除されない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/449c8168-b4d7-efbe-faf5-1103bac16521.png)
データもそのまま、selectもエラーにならない。

　　↓

手動の履歴再同期も実施してみる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/6c006469-0bb3-81d0-741e-ed2455c10279.png)
　　↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/bf40824d-1441-539b-433c-1b63f2f40f92.png)
削除されない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3333083/449c8168-b4d7-efbe-faf5-1103bac16521.png)
データもそのまま、selectもエラーにならない。

ソース側でオブジェクトを削除しても、宛先側では削除されずに最終更新時の状態のまま残ります。

## まとめ・感想
一通り終わりました。

テーブル削除、カラム削除は必要なら宛先側で削除するしかなさそうです。
要注意だと思ったのはレプリカアイデンティティのところ、勉強になりました。
主キー無しテーブルがあって、かつそれを同期対象としたい…という状況があるかは分かりませんが、気を付けなければいけないケースだと思います。

あとはコネクション作成の手順が思ったより大変だった印象です。
社内で話を聞くと、FivetranはSaaSサービスとの接続がより得意なので、SaaSサービスとのコネクション作成ならここまで大変ではないようでした。
機会があればSaaSサービスとの接続も試してみたいです。