## What — タイムトラベル
BigQueryはテーブルの変更履歴を一定期間そのまま保持している。この仕組みがタイムトラベルで、クエリに `FOR SYSTEM_TIME AS OF <時刻>` を付けると「その時刻のテーブル」を読める。バックアップを取っていなくても、直近の事故なら自力で戻せるということ。
> [!warning]
> 保持期間はデフォルトで7日間(データセット単位で2〜7日に変更可)。その範囲を過ぎた時点の状態はもう読めないので、気づいたらすぐ動く。なお、テーブルごと消してしまった場合はこの書き方では戻せず、`UNDROP TABLE` を使う。
戻し方の選択肢は3つ。
- 安全に別テーブルへ退避する
- 既存テーブルを丸ごと置き換える
- 消えた行だけ差し戻す
## How — データを復元する方法
**方法1: 新しいテーブルに復元(推奨)**
過去のデータを新しいテーブルにコピーします。現在のテーブルには一切触らないので、復元結果を見比べてから本番を差し替えられる。
```sql
CREATE TABLE `PROJECT_ID.DATASET.TABLE_RESTORED` AS
SELECT *
FROM `PROJECT_ID.DATASET.TABLE`
FOR SYSTEM_TIME AS OF TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 5 HOUR);
```
**方法2: 既存のテーブルを上書きして復元**
既存のテーブルを過去のデータで置き換えます(注意: 現在のデータは失われます)。参照しているクエリやビューを直さずに済む反面、指定時刻を間違えると二次被害になる。
```sql
CREATE OR REPLACE TABLE `PROJECT_ID.DATASET.TABLE` AS
SELECT *
FROM `PROJECT_ID.DATASET.TABLE`
FOR SYSTEM_TIME AS OF TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 5 HOUR);
```
**方法3: 特定の行だけ復元**
削除された行だけを復元する場合。事故のあとも新しい行が入り続けているテーブルは、丸ごと戻すと最新分まで巻き戻ってしまうので、この差分方式になる。
```sql
-- 削除された行を確認
SELECT *
FROM `PROJECT_ID.DATASET.TABLE`
FOR SYSTEM_TIME AS OF TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 5 HOUR)
WHERE id NOT IN (
SELECT id FROM `PROJECT_ID.DATASET.TABLE`
);
-- 削除された行を挿入
INSERT INTO `PROJECT_ID.DATASET.TABLE`
SELECT *
FROM `PROJECT_ID.DATASET.TABLE`
FOR SYSTEM_TIME AS OF TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 5 HOUR)
WHERE id NOT IN (
SELECT id FROM `PROJECT_ID.DATASET.TABLE`
);
```
まず SELECT で「何が戻るのか」を目視してから INSERT する順番が大事。いきなり書き込むと、重複行を作って壊し直すことになる。
## 関連
- [[Google Cloud]]
- [[データ基盤]]
- [[BigQuery]]
- [[Cloud StorageとBigQuery]]