トランザクション

トランザクションは、読み取りと書き込みの両方の SQL ステートメントのセットであり、ユニットとして処理されます。トランザクション内のすべてのステートメントは、単一のユニットとして適用(つまり、コミット)、または元に戻す(つまり、ロールバック)のいずれかです。トランザクションには、読み取りと書き込みの両方を含めることができます。他のデータベースと同様に、Snowflakeのトランザクションは ACID プロパティ を保証します。

このトピックの内容:

Snowflakeのトランザクションの範囲

トランザクションは単一のセッションに関連付けられます。複数のセッションは同じトランザクションを共有できません。

BEGIN ステートメントを実行することにより、トランザクションを明示的に開始できます。次の状況では、トランザクションを暗黙的に開始できます。

  • AUTOCOMMIT がオフになった後、次の DML ステートメント(ある場合)は、暗黙的にトランザクションを開始します。

  • AUTOCOMMIT がオフの場合、 COMMIT または ROLLBACK の後の最初の DML ステートメント(存在する場合)は、暗黙的にトランザクションを開始します。

トランザクションを開始したら、 COMMIT または ROLLBACK ステートメントを実行してトランザクションを閉じる必要があります。開いているトランザクションのセッションが閉じられると、開いているトランザクションはロールバックされます。

さらに、 AUTOCOMMIT 状態が変更された場合(falseからtrueまたはその逆)、現在実行中のトランザクションは COMMIT になります。

すべてのSnowflakeトランザクションには、トランザクションの ID として機能する一意の開始時間(ミリ秒を含む)が割り当てられます。トランザクションの開始時間の例については、 BEGINの をご参照ください。

自動コミット

デフォルトでは、トランザクションを明示的に開始せずに実行された DML ステートメントは、成功時には自動的にコミットされ、失敗時にはステートメントの最後でロールバックされます。この動作は自動コミットと呼ばれます。この動作は AUTOCOMMIT パラメーターで制御されます。

AUTOCOMMIT の設定に関係なく、DDL ステートメントは常に自動コミットされます。オープントランザクション内で DDL ステートメントを実行すると、次のことが行われます。

  • 開いているトランザクションを コミット します。

  • DDL ステートメントを実行し、コミットします。

CTAS ステートメント(CREATE TABLE AS SELECT ...)は、 DDL として扱われます。その結果、これらも自動コミットされます。

DDL ステートメントは独自のトランザクションであるため、 DDL ステートメントをロールバックすることはできません。 DDL を含むトランザクションは、 ROLLBACK を実行する前に完了しています。ほとんどの DDL ステートメントを元に戻すには、別の DDL ステートメントを実行する必要があります(例えば、作成したテーブルを DROP し、 ALTERed した場合は、テーブルを元の状態に ALTER して戻すか、ドロップしたオブジェクトを UNDROP または再作成します)。

ステートメントのロールバック

明示的に開始されたトランザクションで実行された DML ステートメントに失敗した場合、 DML による変更はロールバックされます。ただし、トランザクションがコミットまたはロールバックされるまで、トランザクションは開いたままになります。

トランザクションとマルチスレッド

複数のセッションが同じトランザクションを共有することはできませんが、単一の接続を使用する複数の スレッド は同じセッションを共有するため、同じトランザクションを共有します。これにより、あるスレッドが別のスレッドで実行した作業をロールバックするなど、予期しない結果が生じる可能性があります。

この状況は、Snowflakeドライバー(Snowflake JDBC ドライバーなど)、またはコネクタ(Python用Snowflakeコネクタなど)を使用するクライアントアプリケーションがマルチスレッド化されている場合に発生する可能性があります。2つ以上のスレッドが同じ接続を共有する場合、それらのスレッドはその接続の現在のトランザクションも共有します。1つのスレッドによる BEGIN、 COMMIT、または ROLLBACK は、その共有接続を使用するすべてのスレッドに影響します。スレッドが非同期で実行されている場合、結果は予測できません。

同様に、1つのスレッドで AUTOCOMMIT 設定を変更すると、同じ接続を使用する他のすべてのスレッドの AUTOCOMMIT 設定に影響します。

AUTOCOMMIT 設定の状態を変更すると、既存のトランザクションがコミットされることに注意してください。

Snowflakeでは、マルチスレッドクライアントプログラムで、少なくとも次のいずれかを実行することをお勧めします。

  • スレッドごとに個別の接続を使用します。

    別々の接続を使用しても、コードが予測できない出力を生成する競合状態に陥ることがあることに注意してください。たとえば、別のスレッドがデータを更新しようとする前に、あるスレッドがデータを削除する場合があります。

  • スレッドを非同期的にではなく同期的に実行して、ステップの実行順序を制御します。

分離レベル

Snowflakeトランザクションは、テーブルの READ COMMITTED 分離をサポートします。READ COMMITTED は、テーブルで現在サポートされている唯一の分離レベルです。

READ COMMITTED 分離

READ COMMITTED 分離では、ステートメントは、ステートメントの開始前にコミットされたデータのみを参照します。コミットされていないデータは表示されません。

ステートメントが複数ステートメントトランザクション内で実行される場合:

  • ステートメントは、 ステートメント が始まる前にコミットされたデータのみを参照します。 同じトランザクション内の連続する2つのステートメントは、最初のステートメントと2番目のステートメントの実行の間に別のトランザクションがコミットされると、異なるデータを見ることができます。

  • ステートメントは、それらの変更がまだコミットされていない場合でも、同じトランザクション 内で 実行された以前のステートメントによって行われた変更を確認します。

リソースのロック

トランザクション操作は、リソースが変更されている間に、テーブルなどのリソースのロックを取得します。ロックは、ロックが解除されるまで他のステートメントがリソースを変更するのをブロックします。

ほとんどの場合、次のガイドラインが適用されます。

  • COMMIT 操作(自動コミットと明示的な COMMITの両方を含む)はリソースをロックしますが、通常は短時間だけです。

  • UPDATE、 DELETE、および MERGE ステートメントは、他の UPDATE、 DELETE、および MERGE ステートメントと並行して実行することを一般的に妨げるロックを保持します。

  • ほとんどの INSERT および COPY ステートメントは、新しいパーティションのみを書き込みます。これらのステートメントは、多くの場合、他の INSERT および COPY 操作と並行して実行できます。また、 UPDATE、 DELETE、または MERGE ステートメントと並行して実行できる場合もあります。

ステートメントによって保持されているロックは、トランザクションの COMMIT または ROLLBACK で解放されます。

ロック待機タイムアウト

ブロックされたステートメントは、待機していたリソースのロックを取得するか、リソースが利用可能になるのを待ってタイムアウトします。ステートメントがブロックする時間(秒単位)は、 LOCK_TIMEOUT パラメーターを設定することで構成できます。

例えば、現在のセッションのロックタイムアウトを2時間(7200秒)に変更する場合:

ALTER SESSION SET LOCK_TIMEOUT=7200;

SHOW PARAMETERS LIKE 'lock%';

+--------------+-------+---------+---------+-------------------------------------------------------------------------------+
| key          | value | default | level   | description                                                                   |
|--------------+-------+---------+---------+-------------------------------------------------------------------------------|
| LOCK_TIMEOUT | 7200  | 43200   | SESSION | Number of seconds to wait while trying to lock a resource, before timing out  |
|              |       |         |         | and aborting the statement. A value of 0 turns off lock waiting i.e. the      |
|              |       |         |         | statement must acquire the lock immediately or abort. If multiple resources   |
|              |       |         |         | need to be locked by the statement, the timeout applies separately to each    |
|              |       |         |         | lock attempt.                                                                 |
+--------------+-------+---------+---------+-------------------------------------------------------------------------------+

デッドロック

デッドロックは、並行トランザクションが互いにロックされているリソースを待機しているときに発生します。

Snowflakeでは、自動コミット DML ステートメントを同時に実行している間、デッドロックは発生しません。ただし、明示的に開始されたトランザクションと各トランザクションの複数のステートメントでデッドロックが発生する可能性があります。Snowflakeはデッドロックを検出し、デッドロックの一部である最新のステートメントを対象として選択します。ステートメントはロールバックされますが、トランザクション自体は開いたままであり、コミットまたはロールバックする必要があります。

ステートメントエラーを許可してトランザクションを中止する

トランザクション内のステートメントエラーでトランザクションを中止するには、セッションレベルまたはアカウントレベルで TRANSACTION_ABORT_ON_ERROR パラメーターを設定します。

トランザクションのコマンドと機能

Snowflakeは、トランザクションをサポートするために次の SQL コマンドを提供します。

さらに、Snowflakeは、セッション内のトランザクションに関する情報を取得するために、次のコンテキスト関数を提供します。

トランザクションの中止

トランザクションがセッションで実行されていて、セッションが突然切断され、トランザクションのコミットまたはロールバックが妨げられた場合、トランザクションはリソースで保持しているロックを含め、デタッチされた状態のままになります。これが発生した場合、トランザクションの中止が必要となる場合があります。

実行中のトランザクションを中止するには、トランザクションを開始したユーザーまたはアカウント管理者が、システム関数 SYSTEM$ABORT_TRANSACTION を呼び出します。

トランザクションが開いたままの場合、Snowflakeは通常、4時間アイドル状態になった後、トランザクションをロールバックします。