Yapay zekâ ile SQL ve veritabanı migration’ı yazmak

Yapay zekâ ile SQL ve migration’ları güvenle yazmak: şemayı ver, salt okunur kullanıcı kullan, EXPLAIN planına bak, index ekle, migration’ı kopyada dene.

Solviera Teknoloji 9 dk okuma

Yapay zekâ ile güvenle SQL yazmak için ajana gerçek şemanı ve salt okunur bir veritabanı kullanıcısı ver, sorgu planını göstermesini iste ve her migration’ı küçük, geri alınabilir ve üretime yaklaşmadan önce verinin bir kopyasında denenmiş tut. Bir yapay zekâ kodlama ajanı sorgu ve migration yazmakta hızlıdır. Risk arada bir kötü SQL yazması değil, kötü bir ifadenin zarar verebileceği bir yerde çalışmasıdır.

Bu rehber sorgu için nasıl prompt yazılacağını, sorguların EXPLAIN ile nasıl kontrol edileceğini, index’in nasıl isteneceğini, kilitlemeyen ve veri kaybettirmeyen migration’ların nasıl yazılacağını, ORM’lerin işin neresinde durduğunu ve bir ajanın üretimin anahtarlarını vermeden MCP üzerinden veritabanına nasıl bağlanacağını anlatıyor. Örnekler PostgreSQL ile; fikirler MySQL ve SQLite için de geçerli.

Sorudan değil, şemadan başla

Bir ajanın yanlış sorgu yazmasının en sık nedeni tahmin etmesidir: aslında account_id olan bir user_id sütunu, tamsayı olarak saklanan bir durum alanı, varlığından haberi olmadığı bir soft-delete bayrağı. Ona önce şemayı ver.

Şemayı nereden alırsın:

  • ORM şema dosyaları. prisma/schema.prisma, Drizzle şema dosyaların, Django models.py, Rails db/schema.rb. Ajan bunları doğrudan okuyabilir; promptta onları göster.
  • Yalnızca yapının dökümü. pg_dump --schema-only tabloları, sütunları, index’leri ve kısıtları veri olmadan yazar:
pg_dump --schema-only --no-owner "$DEV_DATABASE_URL" > schema.sql
  • Bir MCP sunucusu üzerinden salt okunur veritabanı bağlantısı, böylece ajan tabloları listeleyip sütunları kendisi inceleyebilir (aşağıda daha fazlası var).

Sonra şemanın söylemediklerini ekle: kabaca tablo boyutları, hangi sütunların sık sık NULL olduğu ve iş terimlerinin ne anlama geldiği. “Aktif müşteri, son 90 günde siparişi olan müşteridir” cümlesi yanlış bir tahmini önler.

Bir sorgu için prompt:

Using schema.sql: write a PostgreSQL query that returns, for each country,
the number of active customers (an order in the last 90 days) and their
total order value this year. Exclude soft-deleted customers
(deleted_at IS NOT NULL). orders has about 20M rows, customers 400k.
Run it on the dev database, show me the first 10 rows and the EXPLAIN plan.

Promptu Türkçe de yazabilirsin; önemli olan şema, tanımlar ve beklenen çıktı.

Ajan için salt okunur bir kullanıcı kullan

Bir ajan veritabanında herhangi bir şey çalıştırmadan önce ona veriyi değiştiremeyen kendi kullanıcısını ver. PostgreSQL 14 ve sonrasında yerleşik pg_read_all_data rolü bunu kısaltır:

CREATE ROLE agent_ro LOGIN PASSWORD 'change-me';
GRANT pg_read_all_data TO agent_ro;
ALTER ROLE agent_ro SET default_transaction_read_only = on;
ALTER ROLE agent_ro SET statement_timeout = '30s';

pg_read_all_data tüm tablolara yazma hakkı olmadan okuma erişimi verir. İki ALTER ROLE satırı ek güvence sağlar: transaction’lar salt okunur başlar ve kontrolden çıkan bir sorgu 30 saniye sonra iptal edilir. Eski sürümlerde ya da daha dar erişim için bunun yerine CONNECT, şema üzerinde USAGE ve istediğin tablolarda SELECT yetkisi ver.

Bu kullanıcıyı üretime değil, gerçekçi veri içeren bir geliştirme ya da staging veritabanına bağla. Üretim rakamlarına ihtiyacın varsa bir okuma replikası ya da yakın tarihli, anonimleştirilmiş bir kopya kullan.

Sorgu planını oku

Doğru satırları döndüren bir sorgu yine de dakikalar sürebilir. Büyük bir tabloya dokunan her şey için ajandan EXPLAIN çalıştırmasını ve planı sana açıklamasını iste:

EXPLAIN (ANALYZE, BUFFERS)
SELECT c.country, count(DISTINCT c.id)
FROM customers c
JOIN orders o ON o.customer_id = c.id
WHERE o.created_at > now() - interval '90 days'
  AND c.deleted_at IS NULL
GROUP BY c.country;

Tek başına EXPLAIN, veritabanının kullanacağı planı gösterir. ANALYZE sorguyu gerçekten çalıştırır ve gerçek süreleri ve satır sayılarını ekler. Bu önemli: bir UPDATE ya da DELETE üzerinde EXPLAIN ANALYZE veriyi gerçekten değiştirir. Bunları geri aldığın (rollback) bir transaction’a sar ya da yalnızca bir kopyada çalıştır.

Ajandan nelere bakmasını istemeli:

  • Birkaç satırı filtrelediğin büyük tablolarda sıralı taramalar (sequential scan).
  • Tahmini ve gerçek satır sayıları arasında büyük fark; bu eskimiş istatistiklere işaret eder (ANALYZE tablename onları yeniler).
  • Diske taşan sıralamalar ya da hash’ler.
  • Hash join’in daha ucuz olacağı yerde çok sayıda satır üzerinde iç içe döngüler (nested loop).

İyi bir devam promptu: “Bu planı sade bir dille açıkla. En çok zamanı hangi adım alıyor ve neden? Tek bir değişiklik öner ve yeni planı göster.”

Index iste, bedeliyle birlikte

Ajanlar index önermeyi sever. Her index bazı okumaları hızlandırır, o tabloya yapılan her yazmayı yavaşlatır ve disk alanı kaplar. Gerekçesini iste:

The query above does a sequential scan on orders. Suggest at most one
index, explain which queries it helps and what it costs on writes,
and show the EXPLAIN plan with it on the dev database.

Yoğun bir tabloda index’i yazmaları engellemeden oluştur:

CREATE INDEX CONCURRENTLY idx_orders_customer_created
  ON orders (customer_id, created_at);

CONCURRENTLY daha uzun sürer ama çalışırken insert ve update’leri engellemez. Bir transaction bloğu içinde çalışamaz; bu önemli, çünkü birçok migration aracı her migration’ı bir transaction’a sarar. Aracının bunu nasıl ele aldığına bak (çoğunda tek bir migration için transaction’ı kapatma seçeneği var). Eşzamanlı oluşturma başarısız olursa geride geçersiz bir index bırakır; onu silip yeniden oluşturman gerekir.

Güvenle çalıştırılabilecek migration’lar yaz

Bir migration canlı veri üzerinde, çoğu zaman uygulama trafik alırken çalışır. Aşağıdakiler ajandan isteyeceğin ve çıktısında kontrol edeceğin kalıplar.

Genişlet, taşı, daralt

Yeniden adlandırma ya da silme işlemini tek adımda yapma. users.name sütununu users.full_name olarak değiştirmek için:

  1. Genişlet (expand): full_name’i boş bırakılabilir (nullable) bir sütun olarak ekle. İki sütuna da yazan kodu yayınla.
  2. Taşı (migrate): full_name’i name’den parçalar halinde doldur. Okumaları full_name’e geçir.
  3. Daralt (contract): sonraki bir sürümde, name’i okuyan hiçbir şey kalmayınca onu sil.

Her adım tek başına yayınlanıp geri alınabilir. Tek bir ALTER TABLE ... RENAME COLUMN ise çalıştığı anda eski kodun çalışan bütün kopyalarını bozar.

Uzun kilitlerden kaçın

Bazı DDL ifadeleri çalıştığı süre boyunca okumaları ya da yazmaları engelleyen bir kilit alır. Ajandan bunları işaretlemesini ve daha güvenli biçimi kullanmasını iste:

RiskliDaha güvenli
Büyük bir tabloda CREATE INDEXCREATE INDEX CONCURRENTLY
Foreign key’i tek adımda eklemekADD CONSTRAINT ... NOT VALID, sonra ayrı bir adımda VALIDATE CONSTRAINT
Büyük bir tabloda SET NOT NULLBir CHECK (col IS NOT NULL) NOT VALID ekle, doğrula, sonra NOT NULL yap
Sütun tipini değiştirmekYeni sütun ekle, doldur, geçiş yap, eskisini sil
Veri doldurmak için tek dev UPDATEBirkaç binlik satır partileri

PostgreSQL 11’den beri sabit varsayılan değerli bir sütun eklemek tabloyu yeniden yazmaz, yani bu genelde ucuzdur. Ayrıca migration’ın başına bir kilit zaman aşımı koy; böylece uzun bir sorgunun arkasında sıraya girip arkasındaki her şeyi engellemek yerine hızlıca başarısız olur:

SET lock_timeout = '5s';

Geri alınabilir yap

Her migration’ın bir geri dönüş yolu olmalı: ya bir down migration ya da yazılı bir geri alma adımı. Bunu açıkça iste: “Up ve down migration’ı yaz ve hangi adımların veri kaybı olmadan geri alınamayacağını söyle.” Bir sütunu silmek down migration ile geri alınamaz; veri gitmiştir. Silmeyi yedek alındıktan sonra, ayrı ve sonraki bir adımda yapmanın bir nedeni de bu.

Bir kopyada dene

Migration’ı üretimden önce verinin bir kopyasında çalıştır: yakın tarihli bir yedekten geri yüklenmiş bir staging veritabanında ya da üretim boyutunda sahte veri içeren yerel bir veritabanında. Üç şeyi kontrol et: bitiyor mu, ne kadar sürüyor ve uygulama yeni şemayla hâlâ çalışıyor mu. Sonra down migration’ı çalıştır ve onu da kontrol et.

ORM kullanıyorsan: ORM üretsin, ajan incelesin

ORM kullanıyorsan en güvenli akış şu: modeli değiştir, migration’ı ORM üretsin, üretilen SQL’i ajan incelesin.

ORMMigration üretUygulaSQL’i gör
Prismanpx prisma migrate dev --name add_invoice --create-onlynpx prisma migrate deployoluşturduğu migration.sql dosyası
Drizzlenpx drizzle-kit generatenpx drizzle-kit migratemigration klasöründeki SQL dosyaları
Djangopython manage.py makemigrationspython manage.py migratepython manage.py sqlmigrate app 0004
Railsbin/rails generate migration AddFullNameToUsersbin/rails db:migratedb/schema.rb ve migration dosyası

Prisma’nın --create-only seçeneği migration’ı uygulamadan yazar; böylece SQL’i önce düzenleyebilirsin, örneğin CONCURRENTLY eklemek ya da bir adımı bölmek için. Drizzle’da ayrıca şema değişikliklerini migration dosyası olmadan doğrudan uygulayan drizzle-kit push var; yerelde prototip yaparken işe yarar, ama paylaşılan her şey için üretilmiş migration’ları kullan.

Bunların hepsiyle çalışan bir inceleme promptu:

Read the new migration in prisma/migrations/. For each statement, tell me:
does it lock the table, can it lose data, how long will it take on a
table with 20M rows, and is there a safer form? Don't change any files.

Bir ajanı MCP ile veritabanına bağlamak

Bir MCP sunucusu ajanın veritabanını kendisinin sorgulamasını sağlar: tabloları listelemek, bir SELECT çalıştırmak, bir plan okumak. Bu faydalı, ama risk de tam burada; o yüzden salt okunur başla.

Supabase barındırılan bir MCP sunucusu çalıştırıyor. Ekim 2026 itibarıyla adresine read_only=true eklemek her sorguyu salt okunur bir Postgres kullanıcısıyla çalıştırır, project_ref ise onu tek bir projeye bağlar:

claude mcp add --transport http supabase \
  "https://mcp.supabase.com/mcp?project_ref=<your-project-ref>&read_only=true"

Supabase’in kendi önerisi şu: üretim projesini yalnızca görev gerçekten üretim verisi gerektiriyorsa bağla, o zaman da proje kapsamı ve salt okunur mod açık olsun; araç çağrılarının elle onaylanmasını açık tut; sonuçlara göre hareket etmeden önce onları incele, çünkü prompt enjeksiyonuna karşı korumalar kusursuz değil.

Düz PostgreSQL: bağlantı adresinde agent_ro kullanıcınla, bakımı süren bir Postgres MCP sunucusu kullan. En iyi MCP sunucuları yazısı seçenekleri ve salt okunur ayarlarını listeliyor. MCP projesinin eski referans Postgres sunucusu arşivlendi.

CLAUDE.md ya da AGENTS.md dosyana yazmaya değer kurallar:

## Database
- The database MCP server is read-only. Never ask for write access.
- Schema changes go through migrations in prisma/migrations, never direct DDL.
- Never run UPDATE or DELETE without a WHERE clause.
- Run new queries with EXPLAIN on the dev database before proposing them.

Bir ajana asla üretimde yazma yetkisi verme

Esnetilmemesi gereken tek kural bu. Veri satırları talimat gibi okunan metinler içerebilir (bir destek talebi, bir kullanıcı biyografisi) ve onları okuyan bir ajan bu talimatlara uyabilir; buna prompt enjeksiyonu denir. Yanlış anlaşılmış bir istek, yanlış filtreli bir DELETE’e dönüşebilir. Salt okunur bir kullanıcıyla en kötü durum yavaş bir sorgudur. Yazma yetkisiyle ise kesinti ya da kayıp veri.

Güvenli iş bölümü: ajan SQL’i geliştirme verisi üzerinde yazar ve dener; sen incelersin; üretime bir migration aracı ya da bir insan uygular. Sandbox ve izinleri daha geniş ele alan yazı: yapay zekâ kodlama ajanı güvenliği.

AgentVera’da yapmak

AgentVera; Claude Code, Codex ve diğer CLI ajanlarını yan yana çalıştıran, macOS, Windows ve Linux için bir masaüstü uygulaması. Birkaç özellik tam olarak bu iş için yapıldı:

  • Veritabanı yöneticisi: PostgreSQL, MySQL/MariaDB ve SQLite bağlantıları ajanlarınla aynı pencerede; düzenlenebilir tablo görünümü, EXPLAIN destekli bir SQL editörü, DDL’i uygulamadan önce gösteren bir tablo tasarımcısı ve bir ER diyagramı ile. Salt okunur işaretlenen bağlantılar sunucu tarafında da salt okunur açılır; üretim olarak işaretlenen bir bağlantı kırmızı gösterilir ve değişiklikler önce onay ister. Ajanların bir bağlantıyı yerleşik agentvera-db aracıyla kullanmasına izin verebilirsin: erişim varsayılan olarak kapalıdır, açtığında salt okunur modda başlar, ajanlar parolayı hiç görmez ve çalıştırdıkları her sorgu kaydedilir. Veritabanı yöneticisi Pro ve Team planlarında.
  • DB Guard: bir ajan turunu bitirdiğinde değişen migration dosyaları DROP, TRUNCATE, WHERE’siz UPDATE ya da DELETE, CONCURRENTLY’siz CREATE INDEX, yeni kısıtlar ve eksik down adımları gibi risklere karşı taranır. Üretime benzer bir bağlantı seçiliyse risk gerçek tablo boyutlarına göre ölçeklenir. Migration’ı her zaman geri alınan bir transaction içinde bir gölge veritabanında deneyebilir ya da bulguları düzeltmesi için ajana geri gönderebilirsin.
  • MCP yöneticisi: bir veritabanı MCP sunucusunu bir kez kur, her açılışta ajanlarına eklensin.
  • Kod incelemesi: ajan turunu bitirince yazdığı migration ve sorgu kodunu ikinci bir model inceler.

AgentVera’yı indir ve bir geliştirme veritabanında dene.

Toparlarsak

Ajana gerçek şemayı ve geliştirme verisi üzerinde salt okunur bir kullanıcı ver. EXPLAIN çalıştırıp planı açıklamasını, her index’i gerekçelendirmesini ve migration’ları engellemeyen DDL ile küçük, geri alınabilir genişlet-daralt adımlarıyla yazmasını iste. Migration’ları ORM’in üretsin, ajan incelesin; her birini bir kopyada dene ve üretimdeki yazma işlemlerini kendi elinde tut. Net talimatlar bunların hepsini kolaylaştırır; kodlama ajanları için prompt yazmak yazısı bağlamı, planı ve bitti ölçütlerini daha ayrıntılı anlatıyor.

Sık sorulanlar

Yapay zekâ doğru SQL yazabilir mi?

Gerçek şemanı ve verinin yapısını görürse çoğu zaman evet. Yanlış sorguların çoğu tahmin edilen sütun adlarından, eksik join’lerden ya da bilinmeyen NULL’lardan gelir. Ajana şemayı, birkaç örnek satırı ve beklenen sonucu ver; sorguya güvenmeden önce geliştirme veritabanında çalıştırmasını iste.

Bir kodlama ajanını veritabanıma bağlamak güvenli mi?

Salt okunur kullanıcıyla bir geliştirme ya da staging veritabanına, dikkatli olmak şartıyla evet. Yazma yetkisiyle üretime, hayır. Ajan bir isteği yanlış anlayabilir, verideki enjekte edilmiş bir talimata uyabilir ya da WHERE’siz bir DELETE çalıştırabilir. Yazma işlemlerini kendin inceleyip uyguladığın bir migration’ın arkasında tut.

Veritabanı şemamı bir yapay zekâ ajanına nasıl veririm?

ORM’inin tuttuğu şema dosyasını göster (schema.prisma, Drizzle şema dosyaları, Django modelleri) ya da yalnızca yapıyı dök, örneğin pg_dump --schema-only ile. Salt okunur bir veritabanı MCP sunucusu da ajanın tabloları ve sütunları kendisinin listelemesini sağlar.

Migration’ı yapay zekâ mı yazmalı, ORM mi?

Model değişikliğinden migration’ı ORM üretsin, ajan da üretilen SQL’i kilitler, veri kaybı ve eksik adımlar açısından incelesin. Ham SQL’i yalnızca ORM’in ifade edemediği işler için elle (ya da ajanla) yaz; eşzamanlı index oluşturma veya veri doldurma gibi.

Expand and contract (genişlet ve daralt) kalıbı nedir?

Şemayı kesinti olmadan değiştirmenin bir yolu. Önce genişlet: yeni sütunu ya da tabloyu eskisinin yanına ekle. Sonra taşı: ikisine birden yazan kodu yayınla ve eski satırları doldur. En son daralt: eski yapıyı okuyan hiçbir şey kalmayınca onu sonraki bir migration’da kaldır.

Ajanlarını bir masaya topla.

AgentVera’yı ücretsiz indir; kurulu CLI’ların hazır.

Diğer yazılar