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 SCHEMA や DROP 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] 正しい復旧手順
-
(必須) まず、既存の同名オブジェクト(例:
MY_DB)をALTER DATABASE MY_DB RENAME TO MY_DB_OLDのようにリネームするか、DROPして名前の衝突を解消します。 - (
DROP履歴に同名が複数あり、特定のものを指定したい場合のみ)ACCOUNT_USAGEビューで 数値の ID を取得します。
(※SHOW DATABASES HISTORYにはこの数値IDは表示されません) -
UNDROP ... IDENTIFIER(<id>)を実行し、対象を特定して復元します。 - (リネームした場合)必要に応じて、
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 Tables は UNDROP で復元されない
😌 おわりに
テーブルだけでなく、スキーマやデータベース全体にも Time Travel と Fail-safe が適用されるのは非常に強力です。
しかし、その復旧ロジックは、特に「スキーマ DROP 時は、子の設定に関わらずスキーマの保持期間が優先される」という重要な仕様を理解しておく必要があります。
-
Permanent(永続) な DB/スキーマ: Time Travel (最大90日) と Fail-safe で手厚く保護される。 -
Transient(トランジェント) な DB/スキーマ: Fail-safe がない。Time Travel は最大1日であり、1日(24時間) を超えるとすべて失われる。 -
復旧時の注意:
TemporaryやHybrid Tablesは復元されず、同名オブジェクトの衝突はIDENTIFIERでは解消されません。
「コスト削減のために Transient スキーマを使った結果、Time Travel 期間を逃してしまい、スキーマごと全データを失った」という事故が、一番の悪夢です。
「このデータは、消えたら本当に困るデータか?」を自問自答しながら、テーブルだけでなく、それらを入れるスキーマやデータベースのタイプと保持期間も、戦略的に設定してみてくださいね。
📚 参考出典
- Snowflake公式: UNDROP SCHEMA (スキーマDROP時の保持期間の扱いの注記, Hybrid Tables, IDENTIFIER, 復元場所)
- Snowflake公式: UNDROP DATABASE (同名衝突, Hybrid Tables, IDENTIFIERの注記)
- Snowflake公式: SHOW SCHEMAS / DATABASES HISTORY (dropped_on, retention_time 列)
- Snowflake公式: ACCOUNT_USAGE.DATABASES ビュー (database_id)
- Snowflake公式: ACCOUNT_USAGE.SCHEMATA ビュー (schema_id)
- Snowflake公式: CREATE DATABASE (TransientパラメータとFail-safe, 保持期間の上限)
- Snowflake公式: CREATE SCHEMA (TransientパラメータとFail-safe, 保持期間の上限)
- Snowflakeのテーブルガイド:Permanent, Transient, Temporary の違いと「使い分け」
Discussion