Time Travelの理解と使用

Snowflake Time Travelでは、定義された期間内の任意の時点で履歴データ(変更または削除されたデータ)にアクセスできます。Time Travelは、次のタスクを実行するための強力なツールとして機能します。

  • 誤ってまたは意図的に削除された可能性のあるデータ関連オブジェクト(テーブル、スキーマ、およびデータベース)の復元。

  • 過去の重要なポイントからのデータの複製とバックアップ。

  • 指定された期間のデータ使用量/操作の分析。

このトピックの内容:

Time Travelの紹介

Time Travel in Continuous Data Protection lifecycle

Time Travelを使用すると、定義された期間内に次のアクションを実行できます。

  • 更新または削除された過去のデータのクエリ。

  • 過去の特定の時点またはその前に、テーブル、スキーマ、およびデータベース全体のクローンの作成。

  • 削除されたテーブル、スキーマ、およびデータベースを復元します。

定義された時間が経過すると、データは Snowflake Fail-safe に移動され、これらのアクションは実行できなくなります。

Time Travel SQL 拡張

Time Travelをサポートするために、次の SQL 拡張機能が実装されています。

  • AT | BEFORE 句( SELECT ステートメントおよび CREATE ...CLONE コマンド(テーブル名の直後)で指定可能)。この句では、次のパラメーターのいずれかを使用して、アクセスする正確な履歴データを特定します。

    • TIMESTAMP

    • OFFSET (現在時刻との秒単位の時差)

    • STATEMENT (ステートメントの識別子。例:クエリ ID)

  • テーブル、スキーマ、データベース用のUNDROP コマンド。

    Time Travel SQL extensions

データ保持期間

Snowflake Time Travelの重要な要素は、データ保持期間です。

データの削除またはデータを含むオブジェクトの削除など、テーブル内のデータが変更されると、Snowflakeは更新前のデータの状態を保持します。データ保持期間は、この履歴データが保持される日数を指定するため、データに対してTime Travel操作(SELECT、 CREATE ...CLONE、 UNDROP)を実行できます。

標準の保持期間は1日(24時間)であり、すべてのSnowflakeアカウントで自動的に有効になります。

  • Snowflake Standard Editionの場合、アカウントおよびオブジェクトレベル(つまり、データベース、スキーマ、およびテーブル)で保持期間を0(またはデフォルトの1日に戻す)に設定できます。

  • Snowflake Enterprise Edition(またはそれ以上)の場合:

    • 一時データベース、スキーマ、およびテーブルの場合、保持期間を0(またはデフォルトの1日に戻す)に設定できます。同じことが仮テーブルにも当てはまります。

    • 永続データベース、スキーマ、およびテーブルの場合、保持期間は0から90日までの任意の値に設定できます。

注釈

オブジェクトの0日間の保持期間は、オブジェクトのTime Travelを事実上無効にします。

オブジェクトの保持期間が終了すると、履歴データは Snowflake Fail-safe に移動します。

  • 履歴データはクエリに使用できなくなりました。

  • 過去のオブジェクトはクローンできなくなりました。

  • 削除された過去のオブジェクトは復元できなくなりました。

Time Travelのデータ保持期間を指定するには:

  • ACCOUNTADMIN ロールを持つユーザーは、 DATA_RETENTION_TIME_IN_DAYS オブジェクトパラメーターを使用して、アカウントのデフォルトの保持期間を設定できます。

  • データベース、スキーマ、および個々のテーブルを作成するときに、同じパラメータを使用してデフォルトを明示的に上書きできます。

  • データベース、スキーマ、またはテーブルのデータ保持期間はいつでも変更できます。

Time Travelの有効化と無効化

Time Travelの有効化には、タスクは必要ありません。標準の1日の保持期間で自動的に有効になります。

Snowflake Enterprise Editionにアップグレードすると、データベース、スキーマ、およびテーブルに対して最大90日の長いデータ保持期間を構成できるようになります。拡張データ保持には追加のストレージが必要であり、これは毎月のストレージ料金に反映されます。ストレージ料金の詳細については、 Time TravelおよびFail-safeのストレージコスト をご参照ください。

アカウントのTime Travelを無効にすることはできません。ただし、オブジェクトに0の値を指定して DATA_RETENTION_TIME_IN_DAYS 、個々のデータベース、スキーマ、およびテーブルに対して無効にすることはできます。

また、 ACCOUNTADMIN ロールを持つユーザーは、アカウントレベルで DATA_RETENTION_TIME_IN_DAYS を0に設定できます。つまり、アカウントで作成されたすべてのデータベース(およびその後のすべてのスキーマとテーブル)にはデフォルトで保持期間がありません。ただし、このデフォルトは、任意のデータベース、スキーマ、またはテーブルに対していつでも上書きできます。

注意

いずれかのオブジェクトの DATA_RETENTION_TIME_IN_DAYS を0に設定する前に、特にオブジェクトが削除された場合の回復に関連するため、オブジェクトのTime Travelを無効にするかどうかを検討してください。保持期間なしで削除されたオブジェクトを復元する機能は、オブジェクトが削除されたセッションの長さだけ持続します。つまり、保持期間のないオブジェクトが削除された場合、セッションが終了するとオブジェクトを復元できなくなります。

一般的なルールとして、特定のオブジェクトに対して(少なくとも)1日の値を維持することをお勧めします。

オブジェクトのデータ保持期間の指定

デフォルトでは、最大保持期間は1日(つまり、24時間)です。Snowflake Enterprise Edition(およびそれ以上)では、アカウントのデフォルトを最大90日までの任意の値に設定できます。

  • テーブル、スキーマ、またはデータベースを作成するときに、コマンドの DATA_RETENTION_TIME_IN_DAYS パラメーターを使用してアカウントのデフォルトを上書きできます。

  • データベースまたはスキーマに保持期間が指定されている場合、その期間はデフォルトでデータベース/スキーマに作成されたすべてのオブジェクトに継承されます。

オブジェクトのデータ保持期間の変更

If you change the data retention period for a table, the new retention period impacts all data that is active, as well as any data currently in Time Travel. The impact depends on whether you increase or decrease the period:

Increasing Retention

Causes the data currently in Time Travel to be retained for the longer time period.

For example, if you have a table with a 10-day retention period and increase the period to 20 days, data that would have been removed after 10 days is now retained for an additional 10 days before moving into Fail-safe.

これは、10日よりも古いデータや、既にFail-safeに移行しているデータには適用されないことに注意してください。

Decreasing Retention

Reduces the amount of time data is retained in Time Travel:

  • For active data modified after the retention period is reduced, the new shorter period applies.

  • For data that is currently in Time Travel:

    • If the data is still within the new shorter period, it remains in Time Travel.

    • If the data is outside the new period, it moves into Fail-safe.

For example, if you have a table with a 10-day retention period and you decrease the period to 1-day, data from days 2 to 10 will be moved into Fail-safe, leaving only the data from day 1 accessible through Time Travel.

However, the process of moving the data from Time Travel into Fail-safe is performed by a background process, so the change is not immediately visible. Snowflake guarantees that the data will be moved, but does not specify when the process will complete; until the background process completes, the data is still accessible through Time Travel.

To change the retention period for an object, use the appropriate ALTER <オブジェクト> command. For example, to change the retention period for a table:

CREATE TABLE mytable(col1 NUMBER, col2 DATE) DATA_RETENTION_TIME_IN_DAYS=90;

ALTER TABLE mytable SET DATA_RETENTION_TIME_IN_DAYS=30;

注意

Changing the retention period for your account or individual objects changes the value for all lower-level objects that do not have a retention period explicitly set. For example:

  • アカウントレベルで保持期間を変更すると、明示的な保持期間を持たないすべてのデータベース、スキーマ、およびテーブルは、新しい保持期間を自動的に継承します。

  • スキーマレベルで保持期間を変更すると、明示的な保持期間を持たないスキーマ内のすべてのテーブルが新しい保持期間を継承します。

Keep this in mind when changing the retention period for your account or any objects in your account because the change may have Time Travel consequences that you did not anticipate or intend. In particular, we do not recommend changing the retention period to 0 at the account level.

履歴データのクエリ

テーブルに対して DML 操作が実行されると、Snowflakeは定義された期間、テーブルデータの以前のバージョンを保持します。これにより、 AT | BEFORE 句を使用して以前のバージョンのデータをクエリできます。

この句は、保持期間内のテーブル履歴の指定されたポイント、またはその直前のデータのクエリをサポートします。指定されたポイントは、時間ベース(タイムスタンプまたは現在からの時間オフセットなど)にすることも、完了したステートメントの ID にすることもできます(例: SELECT または INSERT)。

例:

  • 次のクエリは、指定されたタイムスタンプで表される日時の時点でテーブルから履歴データを選択します。

    SELECT * FROM my_table AT(TIMESTAMP => 'Mon, 01 May 2015 16:20:00 -0700'::timestamp);
    
  • 次のクエリは、5分前の時点でテーブルから履歴データを選択します。

    SELECT * FROM my_table AT(OFFSET => -60*5);
    
  • 次のクエリは、指定されたステートメントによって行われた変更を含めないで、テーブルから履歴データを選択します。

    SELECT * FROM my_table BEFORE(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726');
    

注釈

AT | BEFORE 句で指定された TIMESTAMP、 OFFSET、または STATEMENT がテーブルのデータ保持期間外にある場合、クエリは失敗し、エラーを返します。

履歴オブジェクトのクローニング

クエリに加えて、テーブル、スキーマ、またはデータベースの CREATE コマンドで CLONE キーワードと AT | BEFORE 句を使用して、オブジェクトの履歴の指定したポイントにオブジェクトの論理複製を作成できます。

例:

  • 次の  CREATE TABLE  コマンドは、指定されたタイムスタンプで表される日付と時刻のテーブルのクローンを作成します。

    CREATE TABLE restored_table CLONE my_table
      AT(TIMESTAMP => 'Mon, 09 May 2015 01:01:00 +0300'::timestamp);
    
  • 次の  CREATE SCHEMA  コマンドは、現在時刻の1時間前に存在していたスキーマとそのすべてのオブジェクトのクローンを作成します。

    CREATE SCHEMA restored_schema CLONE my_schema AT(OFFSET => -3600);
    
  • 次の  CREATE DATABASE  コマンドは、指定されたステートメントの完了前に存在していたデータベースとそのすべてのオブジェクトのクローンを作成します。

    CREATE DATABASE restored_db CLONE my_db
      BEFORE(STATEMENT => '8e5d0ca9-005e-44e6-b858-a8f5b37c5726');
    

オブジェクトのドロップと復元

オブジェクトのドロップ

テーブル、スキーマ、またはデータベースがドロップされても、すぐに上書きされたり、システムから削除されたりすることはありません。代わりに、オブジェクトのデータ保持期間の間保持され、その間はオブジェクトを復元できます。ドロップされたオブジェクトを Fail-safe に移動すると、復元できなくなります。

テーブル、スキーマ、またはデータベースをドロップするには、次のコマンドを使用します。

注釈

オブジェクトをドロップした後、同じ名前のオブジェクトを作成しても、オブジェクトは復元されません。代わりに、オブジェクトの新しいバージョンを作成します。元のドロップされたバージョンは引き続き使用可能であり、復元できます。

ドロップされたオブジェクトを復元すると、オブジェクトは元の場所に復元されます(つまり、新しいオブジェクトは作成されない)。

ドロップされたオブジェクトのリスト

ドロップされたテーブル、スキーマ、およびデータベースは、 HISTORY キーワードを指定した以下のコマンドを使用してリストできます。

例:

SHOW TABLES HISTORY LIKE 'load%' IN mytestdb.myschema;

SHOW SCHEMAS HISTORY IN mytestdb;

SHOW DATABASES HISTORY;

出力には、ドロップされたすべてのオブジェクトと、オブジェクトがドロップされた日時を表示する追加の DROPPED_ON 列が含まれます。オブジェクトが複数回ドロップされた場合、オブジェクトの各バージョンは出力に個別の行として含まれます。

注釈

オブジェクトの保持期間が過ぎ、オブジェクトが削除されると、 SHOW <object_type> HISTORY 出力に表示されなくなります。

オブジェクトの復元

システムからパージされていないドロップされたオブジェクト(つまり、オブジェクトは SHOW <object_type> HISTORY 出力に表示される)は、次のコマンドを使用して復元できます。

UNDROP を呼び出すと、オブジェクトは DROP コマンドが実行される前の最新の状態に復元されます。

例:

UNDROP TABLE mytable;

UNDROP SCHEMA myschema;

UNDROP DATABASE mydatabase;

注釈

同じ名前のオブジェクトが既に存在する場合、 UNDROP は失敗します。既存のオブジェクトの名前を変更する必要があります。名前を変更すると、オブジェクトの以前のバージョンを復元できます。

アクセス制御の要件と名前の解決

オブジェクトをドロップするのと同様に、ユーザーがオブジェクトを復元するには OWNERSHIP 権限が必要です。さらに、ユーザーには、ドロップされたオブジェクトが復元されるデータベースまたはスキーマのオブジェクトタイプに対する CREATE 権限が必要です。

テーブルとスキーマの復元は、完全修飾オブジェクト名が指定されている場合でも、現在のスキーマまたは現在のデータベースでのみサポートされます。

例:テーブルの複数回のドロップおよび復元

次の例では、 mytestdb.public スキーマには2つのテーブル loaddata1proddata1 が含まれています。 loaddata1 テーブルがドロップされて2回再作成され、テーブルの3つのバージョンが作成されます。

  • 現在のバージョン

  • 2番目(つまり、最新)のドロップされたバージョン

  • 最初にドロップされたバージョン

次に、2つのドロップされたバージョンのテーブルを復元する方法の例を示します。

  1. 最初に、同じ名前の現在のテーブルの名前が loaddata3 に変更されます。これにより、タイムスタンプに基づいて、ドロップされたテーブルの最新バージョンを復元できます。

  2. 次に、最新のドロップされたバージョンのテーブルが復元されます。

  3. ドロップされたテーブルの最初のバージョンを復元できるように、復元されたテーブルの名前は loaddata2 に変更されます。

  4. 最後に、ドロップされたテーブルの最初のバージョンが復元されます。

SHOW TABLES HISTORY;

+---------------------------------+-----------+---------------+-------------+-------+---------+------------+------+-------+--------+----------------+---------------------------------+
| created_on                      | name      | database_name | schema_name | kind  | comment | cluster_by | rows | bytes | owner  | retention_time | dropped_on                      |
|---------------------------------+-----------+---------------+-------------+-------+---------+------------+------+-------+--------+----------------+---------------------------------|
| Tue, 17 Mar 2016 17:41:55 -0700 | LOADDATA1 | MYTESTDB      | PUBLIC      | TABLE |         |            | 48   | 16248 | PUBLIC | 1              | [NULL]                          |
| Tue, 17 Mar 2016 17:51:30 -0700 | PRODDATA1 | MYTESTDB      | PUBLIC      | TABLE |         |            | 12   | 4096  | PUBLIC | 1              | [NULL]                          |
+---------------------------------+-----------+---------------+-------------+-------+---------+------------+------+-------+--------+----------------+---------------------------------+

DROP TABLE loaddata1;

SHOW TABLES HISTORY;

+---------------------------------+-----------+---------------+-------------+-------+---------+------------+------+-------+--------+----------------+---------------------------------+
| created_on                      | name      | database_name | schema_name | kind  | comment | cluster_by | rows | bytes | owner  | retention_time | dropped_on                      |
|---------------------------------+-----------+---------------+-------------+-------+---------+------------+------+-------+--------+----------------+---------------------------------|
| Tue, 17 Mar 2016 17:51:30 -0700 | PRODDATA1 | MYTESTDB      | PUBLIC      | TABLE |         |            | 12   | 4096  | PUBLIC | 1              | [NULL]                          |
| Tue, 17 Mar 2016 17:41:55 -0700 | LOADDATA1 | MYTESTDB      | PUBLIC      | TABLE |         |            | 48   | 16248 | PUBLIC | 1              | Fri, 13 May 2016 19:04:46 -0700 |
+---------------------------------+-----------+---------------+-------------+-------+---------+------------+------+-------+--------+----------------+---------------------------------+

CREATE TABLE loaddata1 (c1 number);
INSERT INTO loaddata1 VALUES (1111), (2222), (3333), (4444);

DROP TABLE loaddata1;

CREATE TABLE loaddata1 (c1 varchar);

SHOW TABLES HISTORY;

+---------------------------------+-----------+---------------+-------------+-------+---------+------------+------+-------+--------+----------------+---------------------------------+
| created_on                      | name      | database_name | schema_name | kind  | comment | cluster_by | rows | bytes | owner  | retention_time | dropped_on                      |
|---------------------------------+-----------+---------------+-------------+-------+---------+------------+------+-------+--------+----------------+---------------------------------|
| Fri, 13 May 2016 19:06:01 -0700 | LOADDATA1 | MYTESTDB      | PUBLIC      | TABLE |         |            | 0    | 0     | PUBLIC | 1              | [NULL]                          |
| Tue, 17 Mar 2016 17:51:30 -0700 | PRODDATA1 | MYTESTDB      | PUBLIC      | TABLE |         |            | 12   | 4096  | PUBLIC | 1              | [NULL]                          |
| Fri, 13 May 2016 19:05:32 -0700 | LOADDATA1 | MYTESTDB      | PUBLIC      | TABLE |         |            | 4    | 4096  | PUBLIC | 1              | Fri, 13 May 2016 19:05:51 -0700 |
| Tue, 17 Mar 2016 17:41:55 -0700 | LOADDATA1 | MYTESTDB      | PUBLIC      | TABLE |         |            | 48   | 16248 | PUBLIC | 1              | Fri, 13 May 2016 19:04:46 -0700 |
+---------------------------------+-----------+---------------+-------------+-------+---------+------------+------+-------+--------+----------------+---------------------------------+

ALTER TABLE loaddata1 RENAME TO loaddata3;

UNDROP TABLE loaddata1;

SHOW TABLES HISTORY;

+---------------------------------+-----------+---------------+-------------+-------+---------+------------+------+-------+--------+----------------+---------------------------------+
| created_on                      | name      | database_name | schema_name | kind  | comment | cluster_by | rows | bytes | owner  | retention_time | dropped_on                      |
|---------------------------------+-----------+---------------+-------------+-------+---------+------------+------+-------+--------+----------------+---------------------------------|
| Fri, 13 May 2016 19:05:32 -0700 | LOADDATA1 | MYTESTDB      | PUBLIC      | TABLE |         |            | 4    | 4096  | PUBLIC | 1              | [NULL]                          |
| Fri, 13 May 2016 19:06:01 -0700 | LOADDATA3 | MYTESTDB      | PUBLIC      | TABLE |         |            | 0    | 0     | PUBLIC | 1              | [NULL]                          |
| Tue, 17 Mar 2016 17:51:30 -0700 | PRODDATA1 | MYTESTDB      | PUBLIC      | TABLE |         |            | 12   | 4096  | PUBLIC | 1              | [NULL]                          |
| Tue, 17 Mar 2016 17:41:55 -0700 | LOADDATA1 | MYTESTDB      | PUBLIC      | TABLE |         |            | 48   | 16248 | PUBLIC | 1              | Fri, 13 May 2016 19:04:46 -0700 |
+---------------------------------+-----------+---------------+-------------+-------+---------+------------+------+-------+--------+----------------+---------------------------------+

ALTER TABLE loaddata1 RENAME TO loaddata2;

UNDROP TABLE loaddata1;

+---------------------------------+-----------+---------------+-------------+-------+---------+------------+------+-------+--------+----------------+---------------------------------+
| created_on                      | name      | database_name | schema_name | kind  | comment | cluster_by | rows | bytes | owner  | retention_time | dropped_on                      |
|---------------------------------+-----------+---------------+-------------+-------+---------+------------+------+-------+--------+----------------+---------------------------------|
| Tue, 17 Mar 2016 17:41:55 -0700 | LOADDATA1 | MYTESTDB      | PUBLIC      | TABLE |         |            | 48   | 16248 | PUBLIC | 1              | [NULL]                          |
| Fri, 13 May 2016 19:05:32 -0700 | LOADDATA2 | MYTESTDB      | PUBLIC      | TABLE |         |            | 4    | 4096  | PUBLIC | 1              | [NULL]                          |
| Fri, 13 May 2016 19:06:01 -0700 | LOADDATA3 | MYTESTDB      | PUBLIC      | TABLE |         |            | 0    | 0     | PUBLIC | 1              | [NULL]                          |
| Tue, 17 Mar 2016 17:51:30 -0700 | PRODDATA1 | MYTESTDB      | PUBLIC      | TABLE |         |            | 12   | 4096  | PUBLIC | 1              | [NULL]                          |
+---------------------------------+-----------+---------------+-------------+-------+---------+------------+------+-------+--------+----------------+---------------------------------+