Cerrahi operasyon sırasında cerrahın dokuları geçici olarak kenara çekmesi, kanamayı kontrol etmek için damara hemostatik pens (klemp) koyması ve gerekirse pensi gevşetip dokunun canlılığını test etmesi standart bir prosedürdür. Bu, geri alınabilir bir eylemdir. Pens açıldığında dolaşım kaldığı yerden devam eder; dokuya kalıcı bir hasar verilmemiştir. Ancak cerrah pens takmak yerine bistüriyi alıp ana femoral arteri kökünden keser ve organı masadan aşağı atarsa, ardından anestezi uzmanına dönüp "Tansiyon düştü, kestiğim bacağı geri yerine kaynatalım, işlemi geri alıyoruz" derse bu artık cerrahi bir müdahale değil, cinai bir bilgisizliktir. Biyolojide kesilen uzuv bir parmak şıklatmasıyla geri yerine dikilemez.
İlişkisel veritabanı yönetim sistemlerinde (RDBMS) DELETE ile TRUNCATE arasındaki fark tam olarak bu cerrahi sınırda yatar. Yazılımcının terminalde START TRANSACTION; yazıp arkasına yaslanarak TRUNCATE TABLE users; komutunu çalıştırması ve ardından "Nasılsa işlem (transaction) açtım, beğenmezsem ROLLBACK; der kurtulurum" yanılgısına düşmesi, veritabanı mühendisliğinin en acımasız soğuk duşlarından biridir.
DML vs. DDL: Mantıksal Silme ile Fiziksel İmha
İlişkisel veritabanlarında komutlar rastgele kategorize edilmez. SQL dünyası iki temel eylem kümesine ayrılır:
- DML (Data Manipulation Language):
INSERT,UPDATE,DELETE. Tablonun yapısına dokunmaz; tablonun içindeki satır kayıtlarını işler. - DDL (Data Definition Language):
CREATE,ALTER,DROP,TRUNCATE. Veritabanı şemasını, nesne tanımlarını ve fiziksel dosya yapılarını doğrudan manipüle eder.
+-------------------------------------------------------------------------+
| TRANSACTION İÇİNDE DELETE (DML) |
| |
| START TRANSACTION; |
| DELETE FROM siparisler WHERE durum = 'iptal'; |
| --> Undo Log'a yazılır, satırlar silinmiş olarak işaretlenir. |
| ROLLBACK; |
| --> Undo Log okunur, satırlar geri getirilir. Hasar: 0. |
+-------------------------------------------------------------------------+
+-------------------------------------------------------------------------+
| TRANSACTION İÇİNDE TRUNCATE (DDL - MySQL) |
| |
| START TRANSACTION; |
| TRUNCATE TABLE siparisler; |
| --> DDL algılandı! Mevcut işlem ÖRTÜK OLARAK COMMİT EDİLDİ! |
| --> Tablo fiziksel olarak DROP edilip yeniden CREATE edildi. |
| --> Undo Log tutulmadı, veri blokları işletim sistemine iade edildi. |
| ROLLBACK; |
| --> MySQL Güler: "Neyi geri alayım? Transaction çoktan bitti!" |
+-------------------------------------------------------------------------+
MySQL ve MariaDB'de "Örtük Commit" (Implicit Commit) Tuzağı
MySQL (özellikle InnoDB motoru) çalışırken bir transaction bloğunun içindeyken bir DDL komutu görürse standart SQL davranışını askıya alır. MySQL mimarisi, tablo yapısını değiştiren veya depolama motoru düzeyinde sıfırlama yapan komutların atomik transaction içinde tutulmasına izin vermez.
Geliştirici şu komutları sırayla girdiğinde ne olur?
-- Geliştiricinin zihnindeki hayal dünyası:
START TRANSACTION;
SELECT COUNT(*) FROM uyeler; -- 1.500.000 kayıt
-- "Sadece test amaçlı tabloyu boşaltıyorum, transaction korumam var"
TRUNCATE TABLE uyeler;
-- Hata fark edildi! Tablo canlı ortamdaymış!
ROLLBACK;Oysa MySQL motorunun arka planda icra ettiği gerçek senaryo şudur:
START TRANSACTION;çalışır, aktif transaction başlatılır.TRUNCATE TABLE uyeler;komutu geldiği anda MySQL motoru bir DDL tespit eder. Motor hemen içsel birCOMMITfırlatır! O ana kadar açık olan tüm DML işlemleri kalıcı olarak diske yazılır ve transaction kapatılır.- Tablo işletim sistemi düzeyinde fiziksel olarak düşürülür (
DROP TABLE) ve aynı şemayla boş bir.ibddosyası sıfırdan oluşturulur (CREATE TABLE). Satır satır silme yapılmadığı için InnoDBundo log(geri alma kütüğü) üretmez! - Geliştirici panik içinde
ROLLBACK;yazdığında, MySQL yanıt verir:Query OK, 0 rows affected. Çünkü geri alınacak aktif bir transaction kalmamıştır; transaction 2. adımda sessizce commit edilmiş ve ölmüştür.
Tablodaki 1.5 milyon üye kaydı, şifre hash'leri ve profil bilgileri buharlaşmıştır.
"Ama PostgreSQL'de Rollback Yapılabiliyordu?!"
Bu hataya düşen geliştiricilerin önemli bir kısmı savunma olarak şunu söyler: "Ben lokal ortamımda PostgreSQL kullanıyordum, orada TRUNCATE rollback oluyordu!"
Evet; PostgreSQL'in gelişmiş MVCC (Multi-Version Concurrency Control) ve WAL (Write-Ahead Logging) mimarisi DDL komutlarının birçoğunu (ve TRUNCATE işlemini) bir transaction bloğu içinde izole edebilir. PostgreSQL'de BEGIN; TRUNCATE users; ROLLBACK; dediğinizde tablo geri gelir; çünkü PostgreSQL yeni bir heap dosyası tahsis eder ve rollback durumunda eski dosya tanıtıcısını korur.
Fakat Türkiye'deki web projelerinin ezici çoğunluğu MySQL veya MariaDB üzerinde koşar. İki veritabanı motorunun mimari felsefesini bilmeden komut çalıştırmak, ambulans şoförünün dizel araca benzin doldurup "Ama diğer araba gidiyordu" demesine benzer. Her motorun iç organları farklı çalışır.
DELETE ile TRUNCATE Arasındaki Yaşamsal Farklar
Klinik karar anında bu iki komutun mekanik sonuçlarını bilmek zorundasınız:
| Parametre | DELETE FROM table; | TRUNCATE TABLE table; |
|---|---|---|
| Kategori | DML (Veri Manipülasyonu) | DDL (Veri Tanımlama) |
| İşlem Mantığı | Satır satır siler, her satırı kütüğe yazar. | Tabloyu sıfırdan yeniden oluşturur. |
| İşlem Kaydı (Undo Log) | Çok büyüktür; her satır için geri alma bilgisi saklar. | Yoktur; geri alma bilgisi tutulmaz. |
| Hız | 10 milyon satırda dakikalar sürer, diski boğar. | Mikrosaniyeler içinde biter (anında döner). |
| Auto-Increment Sayacı | Sayacı sıfırlamaz; kaldığı ID'den devam eder. | Sayacı 1e sıfırlar. |
| Tetikleyiciler (Triggers) | ON DELETE tetikleyicilerini tek tek çalıştırır. | Tetikleyicileri tamamen atlar, çalıştırmaz. |
| Transaction Güvenliği | Güvenle ROLLBACK edilebilir. | MySQL'de Örtük Commit yapar; geri alınamaz! |
TRUNCATE bir neşter değil, nükleer silahtır. Neşter satır satır keserken TRUNCATE tüm binayı yıkıp yerine aynı renkte boş bir bina diker.
Gece 02:00 Felaket Yönetimi: Masadaki Hastayı Kurtarmak
Canlı veritabanında sehven TRUNCATE çalıştırıldığında geliştiricinin soğuk terler dökerek destek ekibine yazdığı o meşhur mesaj gelir: "Veritabanında küçük bir senkronizasyon sorunu oldu, son 15 dakikalık yedeği dönebilir miyiz?"
Eğer kurumsal bir veri kurtarma prosedürünüz yoksa, o an şirket için saatlik ciro kaybı başlar:
- Gecelik Snapshot'a Geri Dönüş (RPO Kaybı):
Eğer Point-in-Time Recovery (PITR) altyapınız yoksa dönebileceğiniz tek şey gece 03:00'te alınan günlük yedektir. Bu da bugünün tüm siparişlerinin, ödemelerinin ve müşteri kayıtlarının kalıcı olarak yok olması demektir. - Binlog (Binary Log) ile Noktasal Kurtarma (PITR):
Eğer sunucunuzda MySQL Binary Log aktifse (log_bin = ON), kurtarma mümkündür:- Önce gece alınan tam yedek (mysqldump / xtrabackup) izole bir test sunucusuna açılır.
- Ardından
mysqlbinlogaracıyla o günkü binlog dosyaları taranır:
mysqlbinlog --base64-output=DECODE-ROWS -v /var/log/mysql/binlog.000142 \ | grep -B 5 -A 2 "TRUNCATE TABLE"TRUNCATEkomutunun düştüğü tam pozisyon (stop-position) tespit edilir.- Yedek sunucuya tam o pozisyona kadar olan tüm işlemler yeniden oynatılır (
--stop-position=1849204). - Tablo dışa aktarılıp canlı ortama enjekte edilir.
Bu operasyon en az 3-4 saatlik planlanmamış bir kesinti ve şirketin yönetim kuruluna verilecek utanç verici bir savunma demektir.
Sistemsel Tedavi ve Önleyici Protokoller
Canlı sistemlerde insan hatasını "dikkatli olarak" engelleyemezsiniz. İnsan yorulur, dikkati dağılır, yanlış terminal sekmesinde Entera basar. Koruma mimaride olmalıdır:
- Kullanıcı Yetkilerini Sınırlandırın (Principle of Least Privilege):
Uygulamanın veya geliştiricilerin kullandığı veritabanı kullanıcılarına ASLADROPveyaTRUNCATEyetkisi vermeyin. Canlı ortam kullanıcısının yetkisi sadeceSELECT, INSERT, UPDATE, DELETEolmalıdır. Şema değişiklikleri yalnızca CI/CD pipeline'ları üzerinden denetlenmiş migration araçlarıyla yapılmalıdır. - Production Veritabanına Doğrudan Bağlantıyı Yasaklayın:
Geliştiricilerin masaüstündeki DBeaver, Navicat veya DataGrip ile canlı veritabanına doğrudanrootyetkisiyle bağlanması bir operasyonel intihardır. Canlı veritabanı sadece VPC içinden ve read-only kopyalar üzerinden sorgulanmalıdır. - Safe Updates Modunu Zorunlu Kılın:
MySQL bağlantı parametrelerine--safe-updates(sql_safe_updates = 1) ekleyin. Bu mod,WHEREkoşulu içermeyen veya indeks kullanmayan topluDELETEveUPDATEkomutlarını doğrudan reddeder.
Sonuç
Tıpta temel bir prensip vardır: "Primum non nocere" (Önce zarar verme). Cerrahi müdahale yapacak bir hekimin kestiği damarın anatomik sonuçlarını bilmesi ne kadar gerekliyse; canlı veritabanında komut koşturan bir mühendisin de DML ile DDL arasındaki farkı ve örtük commit mekanizmasını bilmesi o kadar zorunludur.
Transaction açtım diye her komutun geri alınabileceğini sanmak, paraşütsüz uçaktan atlayıp "Nasılsa cebimde emniyet kemeri var" demeye benzer. DDL affetmez; terminale yazdığınız her karakterin arka plandaki motoru nasıl parçaladığını bilmek zorundasınız.