❄️

Snowflake「スキーマごと消した!」を救う UNDROP DATABASE / SCHEMA と、その罠

に公開

😱「あ...本番のスキーマを丸ごと DROP した...」

テーブル(Table)の DROP なら、まだ被害は限定的かもしれません。
ですが、もし操作を誤って、何百ものテーブルが入ったスキーマ(Schema) や、データベース(Database) 自体を DROP してしまったら...

「終わった...」
普通なら、復旧手順を想像するだけで気が遠くなる大惨事です。

しかし、Snowflake なら大丈夫。
テーブルと同じように、スキーマやデータベースにも UNDROP コマンド が用意されています。

なぜなら、Snowflake の強力なデータ保護機能である Time Travel (タイムトラベル)Fail-safe (フェイルセーフ) は、テーブルだけでなく、スキーマやデータベースという「コンテナ(入れ物)」自体にも適用されるからです。

ただし、ここには大きな罠 が潜んでいます。

  • Transient スキーマを DROP したら、1日過ぎたらもう戻せない?」
  • UNDROP したら、同名のDBがあってエラーになった!」
  • Hybrid Tables が戻ってこない!」
  • 「スキーマを戻したら、中のテーブルの保持期間がおかしい?」(←最重要:親の保持が子に優先されます)

この記事では、以前のテーブル編(Snowflakeのテーブルガイド:Permanent, Transient, Temporary の違いと「使い分け」)から一歩進んで、「DB/スキーマ単位の復旧」シナリオと、その時に本当に注意すべきポイントを解説します。

⏳ 1. Time Travel と Fail-safe の基本(おさらい)

まず、2つの機能の役割を簡潔におさらいします。
(※詳細はSnowflakeのテーブルガイド:Permanent, Transient, Temporary の違いと「使い分け」をご参照ください)

Time Travel (タイムトラベル)

  • 目的: ユーザーが自ら 過去の状態に戻るための機能。
  • できること: UNDROP, SELECT ... AT (TIMESTAMP => ...) など。
  • 期間: 0日〜90日(Enterprise Edition以上)。Standard Edition は最大1日。
  • 対象: ユーザーが触れる。コスト(ストレージ代)がかかる。

Fail-safe (フェイルセーフ)

  • 目的: Snowflake 側の最終防衛ライン(災害復旧用)。
  • できること: ユーザーは何もできない。Snowflake サポートへの依頼のみ(ベストエフォート)。
  • 期間: Time Travel 期間終了後、固定で7日間
  • 対象: ユーザーは触れない。コスト(ストレージ代)がかかる。

🏛️ 2. DB/スキーマ と Time Travel

この Time Travel と Fail-safe の仕組みは、データベースとスキーマにも適用されます。

  • Permanent (永続) DB/スキーマ:

    • これがデフォルトです。DATA_RETENTION_TIME_IN_DAYS は Edition に応じて 0〜90日(Standardは最大1日)まで設定可能です。
    • Time Travel と Fail-safe (7日) の両方で保護されます。
  • Transient (トランジェント) DB/スキーマ:

    • CREATE TRANSIENT DATABASE ... で作成します。
    • Time Travel はアカウント設定に関わらず最大1日(0日または1日)に制限されます。
    • Fail-safe は一切効きませんDROP すると、Time Travel 期間終了後に即時パージ(完全削除)されます。

🛠️ 3. もし DB/スキーマ を DROP してしまったら(実務導線)

万が一 DROP してしまった場合、慌てずに以下の手順で確認します。

ステップ1: 履歴の確認 (SHOW ... HISTORY)

まず、DROP された時刻(dropped_on)と保持期間(retention_time)を確認し、UNDROP 可能かどうかの判断に使います。

-- DROP されたスキーマの履歴を表示
SHOW SCHEMAS HISTORY IN DATABASE MY_DB;

-- DROP されたデータベースの履歴を表示
SHOW DATABASES HISTORY;

ステップ2: Time Travel 期間内か確認

dropped_on の時刻から、retention_time(日数)が経過していないか確認します。

  • 期間内 (例: retention_time = 7日, DROP後 3日目):
    ステップ3に進み、UNDROP を実行します。
  • 期間外 (例: retention_time = 1日, DROP後 2日目):
    Transient の場合は復旧不可能です。Permanent の場合はステップ4に進みます。

ステップ3: UNDROP の実行 (Time Travel 期間内)

OWNERSHIP 権限を持つロール(または ACCOUNTADMIN)で UNDROP を実行します。

-- (名前の衝突を解消した後で) スキーマの復元
UNDROP SCHEMA MY_DB.PUBLIC;

-- (名前の衝突を解消した後で) データベースの復元
UNDROP DATABASE MY_DB;

ステップ4: サポートへの相談 (Fail-safe 期間)

Permanent な DB/スキーマが Time Travel 期間を過ぎてしまった場合、**Fail-safe 期間(7日間)**に入っています。
ユーザーは UNDROP できませんが、Snowflake サポートに連絡すれば復旧(ベストエフォート)を依頼できる可能性があります。Transient の場合は Fail-safe がないため、この選択肢はありません。

🚨 4. 初心者がハマる「DB/スキーマ復旧」の罠

UNDROP できるからと安心していると、思わぬ仕様に足元をすくわれることがあります。

罠1:Transient なスキーマ/DB は「1日」が命運を分ける

これが最大の罠です。
コスト削減(Fail-safe 分のストレージ代が不要)のために Transient なデータベースやスキーマを使っている場合、それらは Fail-safe で保護されません

DATA_RETENTION_TIME_IN_DAYS = 1 に設定していても、DROP してから 1日(24時間) を超えると、Time Travel の保持期間外となり永久に失われ、Snowflake サポートでも復旧できません

罠2:UNDROP SCHEMA しても Temporary テーブルは戻ってこない

スキーマの中に Temporary (テンポラリ) テーブルを作成していた場合、そのテーブルの寿命は「セッションの終了」までです。

Permanent なスキーマを UNDROP して復旧させたとしても、DROP 時にセッションが切れた Temporary テーブルは戻ってきません。スキーマを UNDROP しても、セッションをまたいで Temporary テーブルは復旧できないのです。

罠3:Retention=0 の挙動は「入れ物の種類」で異なる

Time Travel を 0 日 (DATA_RETENTION_TIME_IN_DAYS = 0) に設定するとどうなるでしょう?

罠4:「子の保持期間」は「親の保持期間」に上書きされる(※最重要)

DROP/UNDROP の可否は、子オブジェクト側の DATA_RETENTION_TIME_IN_DAYS ではなく、親コンテナ(DB/スキーマ)の保持期間で決まります。

DATA_RETENTION_TIME_IN_DAYS は、DB、スキーマ、テーブルの各レベルで設定できます。では、Time Travel 期間が異なるスキーマとテーブルを DROP したらどうなるでしょう?

結論:スキーマを UNDROP すると、スキーマの保持期間に従って、子オブジェクト(たとえ Transient で Time Travel=1日でも)がまとめて復元されます。

理由(Snowflakeの仕様):
DROP SCHEMADROP DATABASE を実行すると、子の保持期間は尊重されず(無視され)、親コンテナの保持期間が適用されます。

シナリオ:

  • Permanent スキーマ (Time Travel 7日設定)
  • 中に Transient テーブル (Time Travel 1日設定) がある。
  • このスキーマを DROP して 3日後UNDROP SCHEMA を実行すると...
  • → スキーマも、中の Transient テーブルも復元されます。 (親の7日保持が適用されるため)

罠5:IDENTIFIER 句は「同名衝突」を回避しない

IDENTIFIER(<id>) は対象の特定だけであり、命名衝突の回避手段ではありません。
UNDROP DATABASE MY_DB を実行しようとしたときに、すでに MY_DB という名前のデータベースが存在していると、IDENTIFIER を使ったとしてもエラーになります

[Tip] 正しい復旧手順

  1. (必須) まず、既存の同名オブジェクト(例: MY_DB)を ALTER DATABASE MY_DB RENAME TO MY_DB_OLD のようにリネームするか、DROP して名前の衝突を解消します
  2. DROP 履歴に同名が複数あり、特定のものを指定したい場合のみ)ACCOUNT_USAGE ビューで 数値の ID を取得します。
    (※SHOW DATABASES HISTORY にはこの数値IDは表示されません)
  3. UNDROP ... IDENTIFIER(<id>) を実行し、対象を特定して復元します。
  4. (リネームした場合)必要に応じて、MY_DB_OLD を再度リネームして元に戻します。
-- 1. ACCOUNT_USAGE で数値の ID を取得 (遅延あり)
SELECT database_id, name, dropped_on
FROM SNOWFLAKE.ACCOUNT_USAGE.DATABASES
WHERE name = 'MY_DB' AND dropped_on IS NOT NULL
ORDER BY dropped_on DESC
LIMIT 1;

-- 2. (名前衝突を解消した後で) 取得した ID (例: 492) を使って復元
UNDROP DATABASE IDENTIFIER(492);

(※スキーマの場合は SNOWFLAKE.ACCOUNT_USAGE.SCHEMATA.schema_id を使用します)

罠6:Hybrid TablesUNDROP で復元されない

😌 おわりに

テーブルだけでなく、スキーマやデータベース全体にも Time Travel と Fail-safe が適用されるのは非常に強力です。
しかし、その復旧ロジックは、特に「スキーマ DROP 時は、子の設定に関わらずスキーマの保持期間が優先される」という重要な仕様を理解しておく必要があります。

  • Permanent (永続) な DB/スキーマ: Time Travel (最大90日) と Fail-safe で手厚く保護される。
  • Transient (トランジェント) な DB/スキーマ: Fail-safe がない。Time Travel は最大1日であり、1日(24時間) を超えるとすべて失われる。
  • 復旧時の注意: TemporaryHybrid Tables は復元されず、同名オブジェクト の衝突は IDENTIFIER では解消されません。

「コスト削減のために Transient スキーマを使った結果、Time Travel 期間を逃してしまい、スキーマごと全データを失った」という事故が、一番の悪夢です。

「このデータは、消えたら本当に困るデータか?」を自問自答しながら、テーブルだけでなく、それらを入れるスキーマやデータベースのタイプと保持期間も、戦略的に設定してみてくださいね。

📚 参考出典

Discussion