database-migrations
データベースのスキーマ変更、データ移行、ロールバック、ゼロダウンタイムデプロイに関するベストプラクティスを提供します。PostgreSQL・MySQL および主要な ORM(Prisma、Drizzle、Django、TypeORM、golang-migrate)に対応しており、データベースのスキーマ変更を計画・実装する際に活用してください。
description の原文を見る
> Database migration best practices for schema changes, data migrations, rollbacks, and zero-downtime deployments across PostgreSQL, MySQL, and common ORMs (Prisma, Drizzle, Django, TypeORM, golang-migrate). Use when planning or implementing database schema changes.
SKILL.md 本文
データベースマイグレーションパターン
本番システムのための安全で巻き戻し可能なデータベーススキーマ変更。
アクティブ化するタイミング
- データベーステーブルの作成または変更
- カラムまたはインデックスの追加・削除
- データマイグレーション(バックフィル、変換)の実行
- ゼロダウンタイムのスキーマ変更の計画
- 新しいプロジェクトのマイグレーションツール設定
中核原則
- すべての変更がマイグレーション — 本番データベースを手動で変更しない
- マイグレーションは本番環境では順方向のみ — ロールバックは新しい順方向マイグレーションを使用
- スキーママイグレーションとデータマイグレーションは分離 — DDL と DML を1つのマイグレーションで混ぜない
- 本番規模のデータに対してマイグレーションをテスト — 100行で動くマイグレーションが 10M 行でロックする可能性
- マイグレーションはデプロイ後は不変 — 本番環境で実行されたマイグレーションを編集しない
マイグレーション安全性チェックリスト
マイグレーション適用前に確認:
- マイグレーションに UP と DOWN の両方がある(または明示的に取り消し不可と記載されている)
- 大規模テーブルでの全テーブルロックなし(並行操作を使用)
- 新規カラムはデフォルト値がある、またはnull許可(デフォルトなしで NOT NULL を追加しない)
- インデックスは並行作成(既存テーブルの CREATE TABLE にインラインでない)
- データバックフィルはスキーマ変更と分離したマイグレーション
- 本番データのコピーに対してテスト済み
- ロールバック計画が文書化されている
PostgreSQL パターン
カラムを安全に追加
-- GOOD: null許可カラム、ロックなし
ALTER TABLE users ADD COLUMN avatar_url TEXT;
-- GOOD: デフォルト値付きカラム (Postgres 11+ は即座、書き換えなし)
ALTER TABLE users ADD COLUMN is_active BOOLEAN NOT NULL DEFAULT true;
-- BAD: 既存テーブルへの NOT NULL デフォルト値なし (完全な書き換えが必要)
ALTER TABLE users ADD COLUMN role TEXT NOT NULL;
-- テーブルをロックしてすべての行を書き換える
ダウンタイムなしでインデックスを追加
-- BAD: 大規模テーブルで書き込みをブロック
CREATE INDEX idx_users_email ON users (email);
-- GOOD: ノンブロッキング、並行書き込み許可
CREATE INDEX CONCURRENTLY idx_users_email ON users (email);
-- 注: CONCURRENTLY はトランザクションブロック内で実行不可
-- ほとんどのマイグレーションツールは特別な処理が必要
カラムの名前変更(ゼロダウンタイム)
本番環境で直接名前変更しない。expand-contract パターンを使用:
-- Step 1: 新規カラムを追加 (マイグレーション 001)
ALTER TABLE users ADD COLUMN display_name TEXT;
-- Step 2: データをバックフィル (マイグレーション 002、データマイグレーション)
UPDATE users SET display_name = username WHERE display_name IS NULL;
-- Step 3: アプリケーションコードを両カラムに対して読み書き
-- アプリケーション変更をデプロイ
-- Step 4: 旧カラムへの書き込みを停止、削除 (マイグレーション 003)
ALTER TABLE users DROP COLUMN username;
カラムを安全に削除
-- Step 1: アプリケーションからカラムのすべての参照を削除
-- Step 2: カラム参照なしでアプリケーションをデプロイ
-- Step 3: 次のマイグレーションでカラムを削除
ALTER TABLE orders DROP COLUMN legacy_status;
-- Django の場合: SeparateDatabaseAndState を使用してモデルから削除
-- DROP COLUMN を生成せずに(次のマイグレーションで削除)
大規模データマイグレーション
-- BAD: 1つのトランザクションですべての行を更新(テーブルをロック)
UPDATE users SET normalized_email = LOWER(email);
-- GOOD: 進行状況付きバッチ更新
DO $$
DECLARE
batch_size INT := 10000;
rows_updated INT;
BEGIN
LOOP
UPDATE users
SET normalized_email = LOWER(email)
WHERE id IN (
SELECT id FROM users
WHERE normalized_email IS NULL
LIMIT batch_size
FOR UPDATE SKIP LOCKED
);
GET DIAGNOSTICS rows_updated = ROW_COUNT;
RAISE NOTICE 'Updated % rows', rows_updated;
EXIT WHEN rows_updated = 0;
COMMIT;
END LOOP;
END $$;
Prisma (TypeScript/Node.js)
ワークフロー
# スキーマ変更からマイグレーションを作成
npx prisma migrate dev --name add_user_avatar
# 本番環境で保留中のマイグレーションを適用
npx prisma migrate deploy
# データベースをリセット (開発環境のみ)
npx prisma migrate reset
# スキーマ変更後にクライアントを生成
npx prisma generate
スキーマ例
model User {
id String @id @default(cuid())
email String @unique
name String?
avatarUrl String? @map("avatar_url")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
orders Order[]
@@map("users")
@@index([email])
}
カスタム SQL マイグレーション
Prisma で表現できない操作(並行インデックス、データバックフィル)の場合:
# 空のマイグレーションを作成、その後 SQL を手動で編集
npx prisma migrate dev --create-only --name add_email_index
-- migrations/20240115_add_email_index/migration.sql
-- Prisma は CONCURRENTLY を生成できないため、手動で記述
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_users_email ON users (email);
Drizzle (TypeScript/Node.js)
ワークフロー
# スキーマ変更からマイグレーションを生成
npx drizzle-kit generate
# マイグレーションを適用
npx drizzle-kit migrate
# スキーマを直接プッシュ(開発環境のみ、マイグレーションファイルなし)
npx drizzle-kit push
スキーマ例
import { pgTable, text, timestamp, uuid, boolean } from "drizzle-orm/pg-core";
export const users = pgTable("users", {
id: uuid("id").primaryKey().defaultRandom(),
email: text("email").notNull().unique(),
name: text("name"),
isActive: boolean("is_active").notNull().default(true),
createdAt: timestamp("created_at").notNull().defaultNow(),
updatedAt: timestamp("updated_at").notNull().defaultNow(),
});
Django (Python)
ワークフロー
# モデル変更からマイグレーションを生成
python manage.py makemigrations
# マイグレーションを適用
python manage.py migrate
# マイグレーション状態を表示
python manage.py showmigrations
# カスタム SQL 用に空のマイグレーションを生成
python manage.py makemigrations --empty app_name -n description
データマイグレーション
from django.db import migrations
def backfill_display_names(apps, schema_editor):
User = apps.get_model("accounts", "User")
batch_size = 5000
users = User.objects.filter(display_name="")
while users.exists():
batch = list(users[:batch_size])
for user in batch:
user.display_name = user.username
User.objects.bulk_update(batch, ["display_name"], batch_size=batch_size)
def reverse_backfill(apps, schema_editor):
pass # データマイグレーション、巻き戻し不要
class Migration(migrations.Migration):
dependencies = [("accounts", "0015_add_display_name")]
operations = [
migrations.RunPython(backfill_display_names, reverse_backfill),
]
SeparateDatabaseAndState
Django モデルからカラムを削除し、データベースから即座に削除しない:
class Migration(migrations.Migration):
operations = [
migrations.SeparateDatabaseAndState(
state_operations=[
migrations.RemoveField(model_name="user", name="legacy_field"),
],
database_operations=[], # DB にはまだ触らない
),
]
golang-migrate (Go)
ワークフロー
# マイグレーション対を作成
migrate create -ext sql -dir migrations -seq add_user_avatar
# 保留中のすべてのマイグレーションを適用
migrate -path migrations -database "$DATABASE_URL" up
# 最後のマイグレーションを巻き戻し
migrate -path migrations -database "$DATABASE_URL" down 1
# バージョンを強制(ダーティ状態を修正)
migrate -path migrations -database "$DATABASE_URL" force VERSION
マイグレーションファイル
-- migrations/000003_add_user_avatar.up.sql
ALTER TABLE users ADD COLUMN avatar_url TEXT;
CREATE INDEX CONCURRENTLY idx_users_avatar ON users (avatar_url) WHERE avatar_url IS NOT NULL;
-- migrations/000003_add_user_avatar.down.sql
DROP INDEX IF EXISTS idx_users_avatar;
ALTER TABLE users DROP COLUMN IF EXISTS avatar_url;
ゼロダウンタイムマイグレーション戦略
重要な本番環境の変更には expand-contract パターンに従う:
Phase 1: EXPAND
- 新規カラム・テーブルを追加(null許可またはデフォルト値付き)
- デプロイ: アプリは旧と新の両方に書き込み
- 既存データをバックフィル
Phase 2: MIGRATE
- デプロイ: アプリは新から読み込み、両方に書き込み
- データの一貫性を確認
Phase 3: CONTRACT
- デプロイ: アプリは新のみを使用
- 別のマイグレーションで旧カラム・テーブルを削除
タイムラインの例
1日目: マイグレーションが new_status カラムを追加(null許可)
1日目: アプリ v2 をデプロイ — status と new_status の両方に書き込み
2日目: 既存行の一括移行マイグレーションを実行
3日目: アプリ v3 をデプロイ — new_status からのみ読み込み
7日目: 旧 status カラムを削除するマイグレーション
アンチパターン
| アンチパターン | 失敗理由 | より良いアプローチ |
|---|---|---|
| 本番環境での手動 SQL | 監査証跡なし、繰り返し不可 | マイグレーションファイルを常に使用 |
| デプロイされたマイグレーションの編集 | 環境間のドリフトを引き起こす | 新しいマイグレーションを作成 |
| デフォルト値なしの NOT NULL | テーブルをロック、すべての行を書き換え | null許可を追加、バックフィル、制約を追加 |
| 大規模テーブルへのインラインインデックス | ビルド中に書き込みをブロック | CREATE INDEX CONCURRENTLY を使用 |
| スキーマ + データを1つのマイグレーションに | ロールバック困難、長いトランザクション | マイグレーションを分離 |
| コード削除前にカラムを削除 | 欠落カラムでアプリケーションエラー | コード削除後、カラム削除を次のデプロイで実施 |
このスキルを使用するタイミング
- データベーススキーマ変更の計画
- ゼロダウンタイムマイグレーションの実装
- マイグレーションツール設定
- マイグレーション問題のトラブルシューティング
- マイグレーションプルリクエストのレビュー
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- affaan-m
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/affaan-m/everything-claude-code / ライセンス: MIT
関連スキル
hugging-face-trackio
Trackioを使用してMLトレーニング実験を追跡・可視化できます。トレーニング中のメトリクスログ記録(Python API)、トレーニング診断のアラート発火、ログされたメトリクスの取得・分析(CLI)が必要な場合に活用してください。リアルタイムダッシュボード表示、Webhookを使用したアラート、HF Space同期、自動化向けのJSON出力に対応しています。
btc-bottom-model
ビットコインのサイクルタイミングモデルで、加重スコアリングシステムを搭載しています。日次パルス(4指標、32ポイント)とウィークリー構造(9指標、68ポイント)の2カテゴリーにわたる13の指標を追跡し、0~100のマーケットヒートスコアを算出します。ETFフロー、ファンディングレート、ロング/ショート比率、恐怖・貪欲指数、LTH-MVRV、NUPL、SOPR(LTH+STH)、LTH供給率、移動平均倍率(365日MA、200週MA)、週次RSI、出来高トレンドに対応します。市場サイクル全体を通じて買いと売りの両方の推奨を提供します。ビットコインの底値拾い、BTCサイクルポジション、買い時・売り時、オンチェーン指標、MVRV、NUPL、SOPR、LTH動向、ETFの流出入、ファンディングレート、恐怖指数、ビットコインが過熱状態か、マイナーコスト、暗号資産市場のセンチメント、BTCのポジションサイジング、「今ビットコインを買うべきか」「BTCが天井をつけているか」「オンチェーン指標は何を示しているか」といった質問の際にこのスキルを活用します。
protein_solubility_optimization
タンパク質の溶解性最適化 - タンパク質の溶解性を最適化します。タンパク質の特性を計算し、溶解性と親水性を予測し、有効な変異を提案します。タンパク質配列の特性計算、タンパク質機能の予測、親水性計算、ゼロショット配列予測を含むタンパク質エンジニアリング業務に使用できます。3つのSCPサーバーから4つのツールを統合しています。
research-lookup
Parallel Chat APIまたはPerplexity sonar-pro-searchを使用して、最新の研究情報を検索できます。学術論文の検索にも対応しています。クエリは自動的に最適なバックエンドにルーティングされるため、論文の検索、研究データの収集、科学情報の検証に活用できます。
tree-formatting
ggtree(R)またはiTOL(ウェブ)を使用して、系統樹の可視化とフォーマットを行います。系統樹を図として描画する際、ツリーレイアウトの選択、分類学に基づく枝やラベルの色付け、クレードの折りたたみ、サポート値の表示、またはツリーへのオーバーレイ追加が必要な場合に使用してください。系統推定(protein-phylogenyスキルを使用)やドメイン注釈(今後の独立したスキル)には使用しないでください。
querying-indonesian-gov-data
インドネシア政府の50以上のAPIとデータソースに接続できます。BPJPH(ハラール認証)、BOM(食品安全)、OJK(金融適正性)、BPS(統計)、BMKG(気象・地震)、インドネシア中央銀行(為替レート)、IDX(株式)、CKAN公開データポータル、pasal.id(第三者法MCP)に対応しています。インドネシア政府データを活用したアプリ開発、.go.idウェブサイトのスクレイピング、ハラール認証の確認、企業の法的適正性の検証、金融機関ステータスの照会、またはインドネシアMCPサーバーへの接続時に使用できます。CSRF処理、CKAN API使用方法、IP制限回避など、すぐに実行可能なPythonパターンを含んでいます。