Database Migrations

affaan-m/ECC/docs/tr/skills/database-migrations

by affaan-mef648e01899ba3e8dc6371642deaaf64b4477775No license275K starsListed Oct 9, 2026Updated Oct 9, 2026Repository updated 4 days ago

Şema değişiklikleri, veri migration'ları, rollback'ler ve PostgreSQL, MySQL ve yaygın ORM'ler (Prisma, Drizzle, Django, TypeORM, golang-migrate) arasında sıfır kesinti deployment'ları için veritabanı migration en iyi uygulamaları.

AI-generated overview

Guides safe, reversible database schema and data migrations for PostgreSQL, MySQL and common ORMs.

What it does
Provides best-practice guidance for planning and executing database migrations, including safety checklists, PostgreSQL patterns for adding columns and indexes, batched data backfills, and zero-downtime expand-contract strategies. It also documents workflows and example schemas for Prisma, Drizzle, Django, TypeORM and golang-migrate, plus a table of anti-patterns. It produces written migration plans, SQL snippets and ORM command sequences rather than running anything itself.
When to use it
Use when creating or altering tables, adding or removing columns or indexes, running data backfills or transformations, planning zero-downtime schema changes, or setting up migration tooling for a new project.
Requirements
No scripts or runtime dependencies; it is instructions only. Applying the guidance assumes access to a database and the relevant ORM or migration CLI (Prisma, Drizzle, Django, TypeORM, golang-migrate).

Veritabanı Migration Kalıpları

Üretim sistemleri için güvenli, geri alınabilir veritabanı şema değişiklikleri.

Ne Zaman Aktifleştirmeli

  • Veritabanı tabloları oluştururken veya değiştirirken
  • Sütun veya indeks eklerken/kaldırırken
  • Veri migration'ları çalıştırırken (backfill, dönüştürme)
  • Sıfır kesinti şema değişiklikleri planlarken
  • Yeni bir proje için migration araçları kurarken

Temel İlkeler

  1. Her değişiklik bir migration'dır — üretim veritabanlarını asla manuel olarak değiştirmeyin
  2. Migration'lar üretimde sadece ileri — rollback'ler yeni forward migration'lar kullanır
  3. Şema ve veri migration'ları ayrıdır — tek migration'da DDL ve DML'yi asla karıştırmayın
  4. Migration'ları üretim boyutundaki veriye karşı test edin — 100 satırda çalışan migration 10M'de kilitlenebilir
  5. Migration'lar üretimde çalıştıktan sonra değişmezdir — üretimde çalışan migration'ı asla düzenlemeyin

Migration Güvenlik Kontrol Listesi

Herhangi bir migration uygulamadan önce:

  • Migration UP ve DOWN'a sahip (veya açıkça geri alınamaz olarak işaretlenmiş)
  • Büyük tablolarda tam tablo kilitleri yok (concurrent operasyonlar kullan)
  • Yeni sütunlar varsayılanlara sahip veya nullable (varsayılan olmadan NOT NULL asla ekleme)
  • İndeksler concurrent oluşturuluyor (mevcut tablolar için CREATE TABLE ile inline değil)
  • Veri backfill şema değişikliğinden ayrı bir migration
  • Üretim verisinin kopyasına karşı test edilmiş
  • Rollback planı dokümante edilmiş

PostgreSQL Kalıpları

Güvenli Sütun Ekleme

sql
-- İYİ: Nullable sütun, kilit yokALTER TABLE users ADD COLUMN avatar_url TEXT;
-- İYİ: Varsayılanlı sütun (Postgres 11+ anlık, yeniden yazma yok)ALTER TABLE users ADD COLUMN is_active BOOLEAN NOT NULL DEFAULT true;
-- KÖTÜ: Mevcut tabloda varsayılansız NOT NULL (tam yeniden yazma gerektirir)ALTER TABLE users ADD COLUMN role TEXT NOT NULL;-- Bu tabloyu kilitler ve her satırı yeniden yazar

Kesinti Olmadan İndeks Ekleme

sql
-- KÖTÜ: Büyük tablolarda yazmaları engellerCREATE INDEX idx_users_email ON users (email);
-- İYİ: Engellemez, concurrent yazmalara izin verirCREATE INDEX CONCURRENTLY idx_users_email ON users (email);
-- Not: CONCURRENTLY transaction bloğu içinde çalıştırılamaz-- Çoğu migration aracı bunun için özel işleme ihtiyaç duyar

Sütun Yeniden Adlandırma (Sıfır Kesinti)

Üretimde asla doğrudan yeniden adlandırmayın. Expand-contract kalıbını kullanın:

sql
-- Adım 1: Yeni sütun ekle (migration 001)ALTER TABLE users ADD COLUMN display_name TEXT;
-- Adım 2: Veriyi backfill et (migration 002, veri migration'ı)UPDATE users SET display_name = username WHERE display_name IS NULL;
-- Adım 3: Uygulama kodunu her iki sütunu okuma/yazma için güncelle-- Uygulama değişikliklerini deploy et
-- Adım 4: Eski sütuna yazmayı durdur, kaldır (migration 003)ALTER TABLE users DROP COLUMN username;

Güvenli Sütun Kaldırma

sql
-- Adım 1: Sütuna tüm uygulama referanslarını kaldır-- Adım 2: Sütun referansı olmadan uygulamayı deploy et-- Adım 3: Sonraki migration'da sütunu kaldırALTER TABLE orders DROP COLUMN legacy_status;
-- Django için: SeparateDatabaseAndState kullanarak modelden kaldır-- DROP COLUMN oluşturmadan (sonra sonraki migration'da kaldır)

Büyük Veri Migration'ları

sql
-- KÖTÜ: Tüm satırları tek transaction'da günceller (tabloyu kilitler)UPDATE users SET normalized_email = LOWER(email);
-- İYİ: İlerleme ile batch güncellemeDO $$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)

İş Akışı

bash
# Şema değişikliklerinden migration oluşturnpx prisma migrate dev --name add_user_avatar
# Üretimde bekleyen migration'ları uygulanpx prisma migrate deploy
# Veritabanını sıfırla (sadece dev)npx prisma migrate reset
# Şema değişikliklerinden sonra client oluşturnpx prisma generate

Şema Örneği

prisma
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])}

Özel SQL Migration

Prisma'nın ifade edemediği operasyonlar için (concurrent indeksler, veri backfill'leri):

bash
# Boş migration oluştur, sonra SQL'i manuel düzenlenpx prisma migrate dev --create-only --name add_email_index
sql
-- migrations/20240115_add_email_index/migration.sql-- Prisma CONCURRENTLY oluşturamaz, bu yüzden manuel yazıyoruzCREATE INDEX CONCURRENTLY IF NOT EXISTS idx_users_email ON users (email);

Drizzle (TypeScript/Node.js)

İş Akışı

bash
# Şema değişikliklerinden migration oluşturnpx drizzle-kit generate
# Migration'ları uygulanpx drizzle-kit migrate
# Şemayı doğrudan push et (sadece dev, migration dosyası yok)npx drizzle-kit push

Şema Örneği

typescript
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)

İş Akışı

bash
# Model değişikliklerinden migration oluşturpython manage.py makemigrations
# Migration'ları uygulapython manage.py migrate
# Migration durumunu gösterpython manage.py showmigrations
# Özel SQL için boş migration oluşturpython manage.py makemigrations --empty app_name -n description

Veri Migration

python
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  # Veri migration'ı, geri alma gerekmez
class Migration(migrations.Migration):    dependencies = [("accounts", "0015_add_display_name")]
    operations = [        migrations.RunPython(backfill_display_names, reverse_backfill),    ]

golang-migrate (Go)

İş Akışı

bash
# Migration çifti oluşturmigrate create -ext sql -dir migrations -seq add_user_avatar
# Tüm bekleyen migration'ları uygulamigrate -path migrations -database "$DATABASE_URL" up
# Son migration'ı rollback etmigrate -path migrations -database "$DATABASE_URL" down 1
# Versiyonu zorla (dirty durumu düzelt)migrate -path migrations -database "$DATABASE_URL" force VERSION

Migration Dosyaları

sql
-- migrations/000003_add_user_avatar.up.sqlALTER 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.sqlDROP INDEX IF EXISTS idx_users_avatar;ALTER TABLE users DROP COLUMN IF EXISTS avatar_url;

Sıfır Kesinti Migration Stratejisi

Kritik üretim değişiklikleri için expand-contract kalıbını takip edin:

Faz 1: EXPAND  - Yeni sütun/tablo ekle (nullable veya varsayılanlı)  - Deploy: uygulama hem ESKİ hem YENİ'ye yazar  - Mevcut veriyi backfill et
Faz 2: MIGRATE  - Deploy: uygulama YENİ'den okur, her İKİSİNE yazar  - Veri tutarlılığını doğrula
Faz 3: CONTRACT  - Deploy: uygulama sadece YENİ'yi kullanır  - Eski sütun/tabloyu ayrı migration'da kaldır

Zaman Çizelgesi Örneği

Gün 1: Migration new_status sütunu ekler (nullable)Gün 1: App v2 deploy et — hem status hem new_status'a yazGün 2: Mevcut satırlar için backfill migration'ı çalıştırGün 3: App v3 deploy et — sadece new_status'tan okurGün 7: Migration eski status sütununu kaldırır

Anti-Kalıplar

Anti-KalıpNeden Başarısız OlurDaha İyi Yaklaşım
Üretimde manuel SQLDenetim izi yok, tekrarlanamazHer zaman migration dosyaları kullan
Deploy edilmiş migration'ları düzenlemeOrtamlar arası sapma yaratırBunun yerine yeni migration oluştur
Varsayılansız NOT NULLTabloyu kilitler, tüm satırları yeniden yazarNullable ekle, backfill et, sonra kısıt ekle
Büyük tabloda inline indeksBuild sırasında yazmaları engellerCREATE INDEX CONCURRENTLY
Tek migration'da şema + veriRollback zor, uzun transaction'larAyrı migration'lar
Kodu kaldırmadan önce sütun kaldırmaEksik sütunda uygulama hatalarıÖnce kodu kaldır, sonra sütunu sonraki deploy'da kaldır

Source and attribution

Source:affaan-m/ECCindocs/tr/skills/database-migrationsat commitef648e0

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal