削除されたテーブルを復元する

このドキュメントでは、BigQuery で削除されたテーブルを復元(または削除を取り消し)する方法について説明します。削除されたテーブルは、データセットに指定されたタイムトラベル期間内であれば復元できます。これには、明示的な削除だけでなく、テーブルの有効期限の経過による暗黙的な削除も含まれます。タイムトラベル期間を構成することもできます。

削除したデータセットまたはスナップショット全体を復元する方法については、次のリソースをご覧ください。

タイムトラベル期間は、日数を 2~7 日に設定できます。タイムトラベル期間が経過すると、BigQuery はフェイルセーフ期間を開始します。この期間中、削除されたデータはさらに 7 日間自動的に保持されます。フェイルセーフ期間が経過した後、サポート チケットをオープンするなどの方法でテーブルを復元することはできません。

始める前に

削除されたテーブルを復元するために必要な Identity and Access Management(IAM)権限が付与されていることを確認します。

必要なロール

削除されたテーブルを復元するために必要な権限を取得するには、プロジェクトに対する BigQuery ユーザーroles/bigquery.user)IAM ロールを付与するよう管理者に依頼してください。ロールの付与については、プロジェクト、フォルダ、組織へのアクセス権の管理をご覧ください。

必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。

テーブルを復元する

過去のデータを新しいテーブルにコピーすることで、過去のデータからテーブルを復元できます。テーブルが削除されている場合や期限切れの場合でも、タイムトラベル期間内でテーブルを復元する限り、過去のデータをコピーできます。

過去のデータからテーブルを復元しても、ソーステーブルのタグは宛先テーブルにコピーされません。 テーブルのパーティショニング情報も宛先テーブルにコピーされません。元のテーブルのパーティショニング スキームを再作成するには、Cloud Logging で最初のテーブル作成リクエストを表示し、その情報を使用して復元されたテーブルをパーティショニングします。

削除されたテーブルは、タイムトラベル期間内であれば、@<time> 時間デコレータを使用してテーブルを新しいテーブルにコピーすることで復元できます。時間デコレータを使用しても、削除されたテーブルをクエリすることはできません。まずテーブルを復元する必要があります。

@<time> 時間デコレータで次の構文を使用します。

  • tableid@TIMETIME は Unix エポック時刻からの経過時間(ミリ秒単位)です。
  • tableid@-TIME_OFFSETTIME_OFFSET は、現在の時刻からの相対オフセット(ミリ秒単位)です。
  • tableid@0。使用可能な過去のデータの中で最も古いものを指定します。

テーブルを復元するには、次のいずれかのオプションを選択します。

コンソール

Google Cloud コンソールを使用してテーブルの削除を取り消すことはできません。

bq

  1. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

  2. テーブルを復元するには、まずテーブルが存在していたときの UNIX タイムスタンプ(ミリ秒単位)を特定します。Linux の date コマンドを使用して、通常のタイムスタンプ値から UNIX タイムスタンプを生成できます。

    date -d '2023-08-04 16:00:34.456789Z' +%s000
    
  3. 次に、@<time> タイムトラベル デコレータを指定して bq copy コマンドを使用し、テーブルのコピー オペレーションを実行します。

    たとえば、1418864998000 の時点の mydataset.mytable テーブルを新しいテーブル mydataset.newtable にコピーするには、次のコマンドを入力します。

    bq cp mydataset.mytable@1418864998000 mydataset.newtable
    

    (省略可)--location フラグを指定して、その値をロケーションに設定します。

    相対オフセットを指定することもできます。次の例は、1 時間前のテーブルのバージョンをコピーします。

    bq cp mydataset.mytable@-3600000 mydataset.newtable
    
  4. Go

    このサンプルを試す前に、クライアント ライブラリを使用した BigQuery クイックスタートにある Go の設定手順を完了してください。詳細については、BigQuery Go API のリファレンス ドキュメントをご覧ください。

    BigQuery に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、クライアント ライブラリの認証情報を設定するをご覧ください。

    import (
    	"context"
    	"fmt"
    	"time"
    
    	"cloud.google.com/go/bigquery"
    )
    
    // deleteAndUndeleteTable demonstrates how to recover a deleted table by copying it from a point in time
    // that predates the deletion event.
    func deleteAndUndeleteTable(projectID, datasetID, tableID string) error {
    	// projectID := "my-project-id"
    	// datasetID := "mydataset"
    	// tableID := "mytable"
    	ctx := context.Background()
    	client, err := bigquery.NewClient(ctx, projectID)
    	if err != nil {
    		return fmt.Errorf("bigquery.NewClient: %v", err)
    	}
    	defer client.Close()
    
    	ds := client.Dataset(datasetID)
    	if _, err := ds.Table(tableID).Metadata(ctx); err != nil {
    		return err
    	}
    	// Record the current time.  We'll use this as the snapshot time
    	// for recovering the table.
    	snapTime := time.Now()
    
    	// "Accidentally" delete the table.
    	if err := client.Dataset(datasetID).Table(tableID).Delete(ctx); err != nil {
    		return err
    	}
    
    	// Construct the restore-from tableID using a snapshot decorator.
    	snapshotTableID := fmt.Sprintf("%s@%d", tableID, snapTime.UnixNano()/1e6)
    	// Choose a new table ID for the recovered table data.
    	recoverTableID := fmt.Sprintf("%s_recovered", tableID)
    
    	// Construct and run a copy job.
    	copier := ds.Table(recoverTableID).CopierFrom(ds.Table(snapshotTableID))
    	copier.WriteDisposition = bigquery.WriteTruncate
    	job, err := copier.Run(ctx)
    	if err != nil {
    		return err
    	}
    	status, err := job.Wait(ctx)
    	if err != nil {
    		return err
    	}
    	if err := status.Err(); err != nil {
    		return err
    	}
    
    	ds.Table(recoverTableID).Delete(ctx)
    	return nil
    }
    

    Java

    このサンプルを試す前に、クライアント ライブラリを使用した BigQuery クイックスタートにある Java の設定手順を完了してください。詳細については、BigQuery Java API のリファレンス ドキュメントをご覧ください。

    BigQuery に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、クライアント ライブラリの認証情報を設定するをご覧ください。

    import com.google.cloud.bigquery.BigQuery;
    import com.google.cloud.bigquery.BigQueryException;
    import com.google.cloud.bigquery.BigQueryOptions;
    import com.google.cloud.bigquery.CopyJobConfiguration;
    import com.google.cloud.bigquery.Job;
    import com.google.cloud.bigquery.JobInfo;
    import com.google.cloud.bigquery.TableId;
    
    // Sample to undeleting a table
    public class UndeleteTable {
    
      public static void runUndeleteTable() {
        // TODO(developer): Replace these variables before running the sample.
        String datasetName = "MY_DATASET_NAME";
        String tableName = "MY_TABLE_TABLE";
        String recoverTableName = "MY_RECOVER_TABLE_TABLE";
        undeleteTable(datasetName, tableName, recoverTableName);
      }
    
      public static void undeleteTable(String datasetName, String tableName, String recoverTableName) {
        try {
          // Initialize client that will be used to send requests. This client only needs to be created
          // once, and can be reused for multiple requests.
          BigQuery bigquery = BigQueryOptions.getDefaultInstance().getService();
    
          // "Accidentally" delete the table.
          bigquery.delete(TableId.of(datasetName, tableName));
    
          // Record the current time.  We'll use this as the snapshot time
          // for recovering the table.
          long snapTime = System.currentTimeMillis();
    
          // Construct the restore-from tableID using a snapshot decorator.
          String snapshotTableId = String.format("%s@%d", tableName, snapTime);
    
          // Construct and run a copy job.
          CopyJobConfiguration configuration =
              CopyJobConfiguration.newBuilder(
                      // Choose a new table ID for the recovered table data.
                      TableId.of(datasetName, recoverTableName),
                      TableId.of(datasetName, snapshotTableId))
                  .build();
    
          Job job = bigquery.create(JobInfo.of(configuration));
          job = job.waitFor();
          if (job.isDone() && job.getStatus().getError() == null) {
            System.out.println("Undelete table recovered successfully.");
          } else {
            System.out.println(
                "BigQuery was unable to copy the table due to an error: \n"
                    + job.getStatus().getError());
            return;
          }
        } catch (BigQueryException | InterruptedException e) {
          System.out.println("Table not found. \n" + e.toString());
        }
      }
    }

    Node.js

    このサンプルを試す前に、クライアント ライブラリを使用した BigQuery クイックスタートにある Node.js の設定手順を完了してください。詳細については、BigQuery Node.js API のリファレンス ドキュメントをご覧ください。

    BigQuery に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、クライアント ライブラリの認証情報を設定するをご覧ください。

    // Import the Google Cloud client library
    const {BigQuery} = require('@google-cloud/bigquery');
    const bigquery = new BigQuery();
    
    async function undeleteTable() {
      // Undeletes "my_table_to_undelete" from "my_dataset".
    
      /**
       * TODO(developer): Uncomment the following lines before running the sample.
       */
      // const datasetId = "my_dataset";
      // const tableId = "my_table_to_undelete";
      // const recoveredTableId = "my_recovered_table";
    
      /**
       * TODO(developer): Choose an appropriate snapshot point as epoch milliseconds.
       * For this example, we choose the current time as we're about to delete the
       * table immediately afterwards.
       */
      const snapshotEpoch = Date.now();
    
      // Delete the table
      await bigquery
        .dataset(datasetId)
        .table(tableId)
        .delete();
    
      console.log(`Table ${tableId} deleted.`);
    
      // Construct the restore-from table ID using a snapshot decorator.
      const snapshotTableId = `${tableId}@${snapshotEpoch}`;
    
      // Construct and run a copy job.
      await bigquery
        .dataset(datasetId)
        .table(snapshotTableId)
        .copy(bigquery.dataset(datasetId).table(recoveredTableId));
    
      console.log(
        `Copied data from deleted table ${tableId} to ${recoveredTableId}`
      );
    }

    Python

    このサンプルを試す前に、クライアント ライブラリを使用した BigQuery クイックスタートにある Python の設定手順を完了してください。詳細については、BigQuery Python API のリファレンス ドキュメントをご覧ください。

    BigQuery に対する認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、クライアント ライブラリの認証情報を設定するをご覧ください。

    import time
    
    from google.cloud import bigquery
    
    # Construct a BigQuery client object.
    client = bigquery.Client()
    
    # TODO(developer): Choose a table to recover.
    # table_id = "your-project.your_dataset.your_table"
    
    # TODO(developer): Choose a new table ID for the recovered table data.
    # recovered_table_id = "your-project.your_dataset.your_table_recovered"
    
    # TODO(developer): Choose an appropriate snapshot point as epoch
    # milliseconds. For this example, we choose the current time as we're about
    # to delete the table immediately afterwards.
    snapshot_epoch = int(time.time() * 1000)
    
    # ...
    
    # "Accidentally" delete the table.
    client.delete_table(table_id)  # Make an API request.
    
    # Construct the restore-from table ID using a snapshot decorator.
    snapshot_table_id = "{}@{}".format(table_id, snapshot_epoch)
    
    # Construct and run a copy job.
    job = client.copy_table(
        snapshot_table_id,
        recovered_table_id,
        # Must match the source and destination tables location.
        location="US",
    )  # Make an API request.
    
    job.result()  # Wait for the job to complete.
    
    print(
        "Copied data from deleted table {} to {}".format(table_id, recovered_table_id)
    )

タイムトラベル期間によって許されている期間後にテーブルを復元することが想定される場合は、テーブルのスナップショットを作成します。 さらに詳しい内容については、テーブル スナップショットの概要をご覧ください。

論理ビューを直接復元することはできません。詳細については、ビューを復元するをご覧ください。

テーブルの復元のトラブルシューティング

過去のタイムスタンプを使用して、削除されたテーブルをクエリする

過去に削除されたテーブルのタイムスタンプ デコレータを使用したクエリ、または FOR SYSTEM_TIME AS OF を使用した宛先テーブルへの結果の保存による、テーブルデータの復元はできません。これらの方法を使用すると、次のエラーが生じます。

Not found: Table myproject:mydataset.table was not found in location LOCATION

テーブルをコピーするには、テーブルを復元するの手順に沿って操作してください。

エラー: VPC Service Controls: Request is prohibited by organization's policy

Google Cloud Shell からコピーのコマンドを実行しようとすると、次のようなエラーが発生することがあります。

BigQuery error in cp operation: VPC Service Controls: Request is prohibited by organization's policy

VPC Service Controls(SC)で Google Cloud コンソールから Cloud Shell を使用することはサポートされていません。これは、サービス境界外のリクエストとして扱われ、VPC SC が保護するデータへのアクセスが拒否されるためです。この問題を回避するには、Google Cloud CLI を使用して Cloud Shell を起動し、ローカルに接続します。

エラー: Latest categories are incompatible with schema

Google Cloud Shell からコピーのコマンドを実行すると、次のようなエラーが表示されることがあります。

Latest categories are incompatible with schema at TIMESTAMP

このエラーには、次のような原因が考えられます。

このエラーを解決する方法は以下のとおりです。

  1. 宛先テーブルのスキーマを必ず同一にします。また、元のテーブルの列が宛先テーブルから欠落していないことを確認します。
  2. 元のテーブルのスキーマにない列レベルのポリシータグを、宛先テーブルから削除します。

エラー: BigQuery error in cp operation: Invalid time travel timestamp

Google Cloud Shell から bq copy コマンドを実行すると、次のようなエラーが表示されることがあります。

BigQuery error in cp operation: Invalid time travel timestamp 1744343690000 for
table PROJECT_ID:DATASET_ID.TABLE_ID@1744343690000.
Cannot read before 1744843691075

このエラーは、タイムトラベル期間の前かテーブルの作成時刻より前のテーブルの状態からデータを復元しようとしていることを示します。これはサポートされていません。エラー メッセージには、テーブルデータの読み取りに使用できる最新のタイムスタンプが含まれています。bq copy コマンドでエラーのタイムスタンプを使用します。

このエラーは、負のタイムスタンプ値(TABLE@-1744963620000 など)を指定した場合にも発生します。- 符号と一緒に使用できる時間オフセットを使用してください。

BigQuery error in cp operation: Invalid time travel timestamp 584878816 for
table PROJECT_ID:DATASET_ID.TABLE_ID@584878816.
Cannot read before 1744843691075

このエラー メッセージは、bq cp コマンドにオフセットとして負のタイムスタンプ値が含まれており、CURRENT_TIMESTAMP - PROVIDED TIMESTAMP でテーブルを読み取ろうとしたことを示しています。この値は通常、1970 年のタイムスタンプです。この問題を回避するには、テーブル デコレータの値を設定するときにオフセット値またはタイムスタンプ値を確認し、- 符号を適切に使用します。

次のステップ