BigQuery で DML が無制限で利用可能に
Google Cloud Japan Team
※この投稿は米国時間 2020 年 3 月 4 日に、Google Cloud blog に投稿されたものの抄訳です。
Google Cloud のエンタープライズ データ ウェアハウスである BigQuery でデータ操作言語(DML)ステートメント(INSERT、UPDATE、DELETE、MERGE など)を使用すると、BigQuery に保存されているデータを追加、変更、削除できるようになります。BigQuery の DML では、単一のジョブでテーブル内の多数の行の挿入、更新、削除がサポートされています。
BigQuery チームでは、DML 機能を継続的に改良して、パフォーマンス、スケーラビリティ、ボリュームの向上を目指しています。このたび、BigQuery で DML オペレーションの割り当て制限がすべて撤廃され、テーブルに対して数に制限なく DML ステートメントを実行できるようになりました。このリリースにより、更新の間で競合が発生することなく、より高い頻度でテーブルを更新することが可能になります。具体的には、変更データ キャプチャ(CDC)などのシナリオで、より高い頻度で変更を適用できるため、データの鮮度が向上します。
このブログでは、これを可能にする BigQuery の変更点について説明します。INSERT DML ステートメント(新しい行をテーブルに追加するのみ)と区別するために、UPDATE、MERGE、DELETE は変更 DML ステートメントと呼びます。
DML ステートメントの実行
BigQuery はマルチバージョンのデータベースです。テーブルに対して行の変更または追加を行うトランザクションは ACID 準拠です。BigQuery はスナップショット分離(Snapshot Isolation) を使用して、テーブルに対する複数の同時オペレーションを処理します。DML ステートメントを含むクエリジョブを送信することで、DML オペレーションを BigQuery に送信できます。ジョブが開始されると、BigQuery はクエリで使用するテーブルの読み取りに使用するスナップショット タイムスタンプを決定します。クエリで使用する入力テーブルで(FOR SYSTEM_TIME AS OF を使用して)スナップショット タイムスタンプが明示的に指定されていない限り、BigQuery はこのスナップショット タイムスタンプをテーブルの読み取りに使用します。このタイムスタンプにより、ジョブで操作対象となるテーブル内のデータのスナップショットが決まります。具体的には、BigQuery は DML ステートメントのターゲットであるテーブルのこのスナップショットに対して、生成した変更内容を適用しようとします。
BigQuery は、テーブルのロックではなく、楽観的並行性制御という方法を使用します。ジョブを commit する時点で、このジョブによって生成された変更内容が、このジョブが実行されていたときにこのテーブルに対して行われたその他の変更内容と競合しないかをチェックします。競合がある場合は、commit オペレーションを中止し、ジョブを再試行します。そのため、最初に commit されたジョブが優先されます。言い換えると、短い DML 変更オペレーションを多数実行した場合、実行時間が長いオペレーションほど優先度が低くなることが考えられます。
同時更新の失敗時における自動再試行
1 つのテーブルに対して 2 つの変更 DML ステートメントを同時に実行した場合、2 つのステートメントが同じパーティションのデータを変更することがない限り成功します。同じパーティションを変更しようとする 2 つのジョブを実行した場合、同時更新が失敗することがあります。BigQuery では、以前はこのような同時更新オペレーションが失敗し、アプリケーションで再試行する必要がありましたが、今回こうした失敗が自動的に対処されるようになりました。その仕組みとしては、BigQuery がジョブを再開し、クエリで使用されるテーブルを読み込む際に使う新しいスナップショット タイムスタンプを最初に決定します。次に、前述のプロセスを使用して新しいスナップショットに変更を適用します。BigQuery は同時更新に失敗しても、テーブルに対して最大 3 回まで再試行します。今回の変更により、ユーザーが直面していた同時更新エラーの数を大幅に削減できます。
変更 DML ステートメントのキュー
以前、BigQuery では、テーブルに対して 24 時間で実行できる DML ステートメント数が 1,000 件まででしたが、この割り当て上限がなくなりました。現在の仕組みでは、BigQuery が任意の時点でテーブルに対して同時実行する変更 DML ステートメントは一定数で、その数を超えてテーブルに送信された変更 DML ジョブは、自動的に PENDING 状態でキューに登録されます。先に実行中だったジョブが終了すると、次の PENDING ジョブがキューから出されて実行されます。
このような新しいキューの動作により、実際は DML オペレーションに要する時間が長くなったように思われることがあります。他のオペレーションの完了を待つ間、DML オペレーションが PENDING 状態で存在できるためです。このような状況が起こっているかどうかを知りたい場合は、DML ジョブの状態を確認してください。ジョブの状態が PENDING の場合は、このキューの動作が原因でオペレーション時間が長くなっている可能性があります。また、ジョブの実行後にこの情報を確認することもできます。ジョブの統計情報として時刻が記録されるタイミングは 3 回あります。BigQuery サーバーがリクエストを受信してジョブを実行したとき(作成時刻)、ジョブの実行が開始され RUNNING 状態になったとき(開始時刻)、クエリが完了したとき(終了時刻)です。作成時刻と開始時刻がずれている場合は、なんらかの理由でジョブがキューに登録されたことを表しています。
BigQuery では、各テーブルで最大 20 件までそのようなジョブを PENDING 状態でキューに登録できます。そのテーブルに対して同時実行される読み込みジョブまたは INSERT DML ステートメントは、すぐさま開始され、変更オペレーションの実行に影響しないため、20 件の上限のカウントには含まれません。
INSERT DML ステートメント
BigQuery では通常、単一のテーブルに書き込みを行う INSERT DML ステートメントの同時実行数に制限を設けていません。ローリング ウィンドウに相当する直近 24 時間で、BigQuery はテーブルへの挿入を行う最初の 1,000 件のステートメントを同時に実行します。システムの過負荷を防ぐため、同時実行できる INSERT DML ステートメントを一定数に保ちながら、その上限を超えるものはキューに登録されます。前のジョブが終了すると、次の PENDING ジョブがキューから出されて実行されます。キューイングの開始後は、BigQuery でテーブルに対して最大 100 件の INSERT DML ステートメントをキューに登録できます。
DML ステートメントに関するベスト プラクティス
BigQuery は任意の規模の変更にスケールできます。前述した仕様変更により、BigQuery が提供する DML サポートで規模の小さい変更にも対応できます。一般に、テーブルに対して実行可能な DML ステートメントの件数は、各オペレーションの実行にかかる時間で決まります。最高のパフォーマンスを得るために推奨されるパターンは次のとおりです。
●更新や削除の対象となるのが、通常、古いデータや日付によって偏りのあるデータである場合は、パーティション分割テーブルを使用します。これにより、変更が特定のパーティションだけに制限されるため、更新プロセスを高速化できます。
●変更された行がデータの偏りのある部分に属するクラスタ化テーブルに対しては、一般にパフォーマンスに優れるため更新を使用します。これにより、変更が特定の一連ブロックのみに制限されるため、読み取りと書き込みが必要なデータの量が削減されます。
●DML オペレーションをより大きなグループにまとめ、規模の小さいオペレーションの実行コストを平均化します。
●各パーティションのデータ量が小さく、各更新の際にテーブル内の大部分のパーティションを変更している場合は、テーブルのパーティショニングを行わないようにします。これにより、メタデータの変更が抑えられ、更新のパフォーマンスが改善されます。
詳しくは、BigQuery のデータ操作言語をご覧ください。
- By Google Cloud シニア スタッフ ソフトウェア エンジニア Pavan Edara