BULK APIを利用して、大量データロード時のレコードロックについて

##SalesforceにBULK APIの概要について、以下の紹介があります。

>Bulk API は、REST 規則に基づいており、大規模データセットの読み込みまたは削除用に最適化されています。Bulk API を使用して複数のバッチを送信することにより、多数のレコードを非同期でクエリ、queryAll、挿入、更新、更新/挿入または削除できます。バッチはバックグラウンドで処理されます。

ただし、パラレルで複数のバッチを組込む場合、データにより、レコードロックが発生する場合があります。またはデータロードとsalesforce内のその他の自動化処理と合せてレコードロックが発生する場合もありますので、
今回、レコードロックが発生しやすいパターンとその場合の解決案を検討します。


####◆主従関係Master-Detail Relationships
----------------------------------------------------
<B>・Salesforce仕組：</B>Detailレコードを登録する時、Salesforce上そのDetailに対応するMasterレコードが自動的にロックされる。
<B>・ロックエラー発生例：</B>パラレルで異なるバッチに同一Master IDを持っているDetailレコードを同時に登録する場合、ロックエラー発生のリスクが高いです。
<B>・回避方法：</B>①同一Master IDを持っているDetailレコードが同一バッチ内に実行するようにする。
　　　　　　②MasterレコードのIDでデータロードの実行順をソートする。


####◆積み上げ集計項目Roll-up Summary Fields
----------------------------------------------------
<B>・Salesforce仕組：</B>Master-Detailの中、Masterレコードに積み上げ集計項目ある場合、Detailレコードが更新する度に、積み上げ集計項目をリフレッシュして更新するために、Salesforce上そのDetailに対応するMasterレコードが自動的にロックされる。
<B>・ロックエラー発生例：</B>パラレルで異なるバッチに同一Master IDを持っているDetailレコードを同時に登録する場合、ロックエラー発生のリスクが高いです。
<B>・回避方法：</B>①同一Master IDを持っているDetailレコードが同一バッチ内に実行するようにする。
　　　　　　②MasterレコードのIDでデータロードの実行順をソートする。
　　　　　　③積み上げ集計項目をレポートに抽出する。


####◆参照関係Lookup Relationships
----------------------------------------------------
<B>・Salesforce仕組：</B>参照関係を持っている子レコードを登録する時、Salesforce上その子に対応する親レコードが自動的にロックされる。
<B>・ロックエラー発生例：</B>パラレルで異なるバッチに同一親IDを持っている子レコードを同時に登録する場合、ロックエラー発生のリスクが高いです。
<B>・回避方法：</B>①同一親IDを持っている子レコードが同一バッチ内に実行するようにする。
　　　　　　②参照項目が必須ではない場合、
　　　　　　「参照レコードが削除される場合の対処方法」について、
　　　　　　「参照関係に含まれる参照レコードは削除できません」を設定しなくて、
　　　　　　「この項目をクリアします」を設定する。この方法はバッチの実行時間が短縮できる。


####◆トリガーTriggers
----------------------------------------------------
<B>・Salesforce仕組：</B>レコードをロードする時、トリガーがある場合、トリガーを発火できる。
<B>・ロックエラー発生例：</B>バッチを実行して、更新処理があるトリガーを発火させて、ロックエラー発生のリスクが高いです。
<B>・回避方法：</B>①データロードするユーザに対し、トリガーを発火させないように設定する。
　　　　　　②データロードする場合、トリガーを実行しないように処理を追加する。


####◆ワークフローWorkflow Rules
----------------------------------------------------
<B>・Salesforce仕組：</B>トリガーと同様
<B>・ロックエラー発生例：</B>トリガーと同様
<B>・回避方法：</B>データロードする間、ワークフローを実施しないように設定する。


####◆グループメンバーGroup Membership Locks
----------------------------------------------------
<B>①グループメンバー（ユーザオブジェクトとか）は、ロックエラーの発生確率を次の方法で下げることができます。</B>
　・各グループメンテナンスプロセスが重ならないように慎重にスケジュールする
　・インテグレーションやその他の自動化されたグループメンテナンスプロセスに再試行ロジックを実装して、エラーから回復してロックを取得できるようにする
<B>②データロードで以下の場合、シリアルプロセスでデータロードする必要があります。</B>
　・ユーザを登録し、そのユーザをロールに割り当てる場合
　・ユーザのロールを変更する場合
　・ロールの階層、又はテリトリー階層を変更する場合
　・ロール階層の構成、又はテリトリー階層の構成を変更する場合
　・public／personalグループ、ロール、テリトリー、キューにメンバを追加／削除する場合
　・Accountの所有者を変更する、その所有者が１つ以上のコミュニティロール、又はポータルロールが関連している場合


####◆バッチの重複実行Overlapping Runs
----------------------------------------------------
<B>・回避方法：</B>データロードバーチの実行は他のバッチと重複にならないようにスケジュールする。
<br/>
<br/>
####◆SURPRISE
----------------------------------------------------
<B>Degree of Parallelism</B>
Degree of Parallelismについて、以下の計算式となります。
![Degree of Parallelism.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496589/8d94e3f2-9148-1493-eb98-83bd0258e498.png)
　・Work Completed:（シリアルで１つのバッチの実行時間 * バッチ数）時間
　・Run Time:業務上にデータロードバッチの実行必要な最大時間、又はパラレルで実際のバッチ実施時間
　　　　　　　※実行時間に対し制限がある場合
　・Degree of Parallelism:パラレルで設定する必要なバッチ数

『Degree of Parallelism』の使用用途は以下の考えがあります：
業務上にデータロードバッチの実行時間について、制限がある場合、
制限の時間内にパラレルで一回どれぐらいのバッチ数を取組む必要かは上記の計算式で推測できて、
されに、一回に処理する必要なデータ量もシミュレーションできて、サーバにより、処理可能であるかどうかもシミュレーションできると思います。

<B>Throughput</B>
Throughputについて、以下の計算式となります。
![Throughput.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496589/8171e827-a5be-620d-3e7b-7161aaae0760.png)
　・Records Loaded:処理必要なデータ量
　・Run Time:業務上にデータロードバッチの実行必要な最大時間、又はパラレルで実際のバッチ実施時間

<B>バッチ実行結果分析は以下のイメージ</B>
![結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/496589/c568fb5e-8450-4cf5-f881-c693c34189a9.png)
<br/>
<br/>
参考リンク：
[・グループメンバーシップのロック](https://developer.salesforce.com/docs/atlas.ja-jp.228.0.draes.meta/draes/draes_group_membership_locking.htm)
[・Maximizing Parallelism and Throughput Performance](
https://developer.salesforce.com/wiki/the_salesforce_bulk_api_maximizing_parallelism_and_throughput_performance_when_integrating_or_loading_large_data_volumes)