DELETE vs TRUNCATE vs DROP Farkları
Giriş — Üç Farklı "Silme" Komutu
SQL'de bir şeyleri silmek istediğinde karşına üç farklı komut çıkar: DELETE, TRUNCATE ve DROP. Hepsi bir şeyleri "siler" ama yapıları ve sonuçları çok farklıdır. Bu farkları bilmemek ciddi sorunlara yol açabilir.
🎯 Analoji: Bir ev düşün. - DELETE → Evdeki belirli eşyaları çöpe atarsın (istediğin eşyaları seçebilirsin) - TRUNCATE → Evin içini komple boşaltırsın (tüm eşyalar gider ama ev duruyor) - DROP → Evi yıkarsın (ev de, eşyalar da, her şey gider)
DELETE — Satır Bazında Silme
DELETE DML komutudur ve tablodaki belirli satırları siler.
Temel Sözdizimi
DELETE FROM tablo_adi
WHERE kosul;Koşullu Silme
-- Belirli bir müşteriyi sil
DELETE FROM customers WHERE customer_id = 11;
-- Query OK, 1 row affected
-- Aktif olmayan müşterileri sil
DELETE FROM customers WHERE is_active = FALSE;
-- Belirli tarihten önceki siparişleri sil
DELETE FROM orders WHERE order_date < '2023-01-01' AND status = 'cancelled';
-- Stoku 0 ve aktif olmayan ürünleri sil
DELETE FROM products WHERE stock_quantity = 0 AND is_active = FALSE;WHERE Olmadan DELETE — Tüm Satırları Sil
-- ⚠️ TÜM satırları siler!
DELETE FROM order_items;
-- Tüm sipariş kalemleri silindi
-- Bu, TRUNCATE'e benzer ama çok daha yavaş (her satırı tek tek siler)DELETE ile LIMIT
-- En eski 10 iptal edilmiş siparişi sil
DELETE FROM orders
WHERE status = 'cancelled'
ORDER BY order_date ASC
LIMIT 10;DELETE ve Foreign Key
Foreign key ilişkisi olan tablolarda silme işlemi kısıtlanabilir:
-- Müşteri silmeye çalışalım (ama bu müşterinin siparişleri var)
DELETE FROM customers WHERE customer_id = 1;
-- ERROR: Cannot delete or update a parent row: a foreign key constraint fails
-- Önce child kayıtları silmelisin:
-- 1. Sipariş kalemlerini sil
DELETE FROM order_items WHERE order_id IN (
SELECT order_id FROM orders WHERE customer_id = 1
);
-- 2. Siparişleri sil
DELETE FROM orders WHERE customer_id = 1;
-- 3. Artık müşteriyi silebilirsin
DELETE FROM customers WHERE customer_id = 1;Eğer ON DELETE CASCADE tanımlıysa, parent silindiğinde child'lar otomatik silinir:
-- orders → order_items ilişkisinde CASCADE varsa:
DELETE FROM orders WHERE order_id = 1;
-- order_items'taki order_id = 1 olan kayıtlar da otomatik silinirDELETE'in Özellikleri
| Özellik | DELETE |
|---|---|
| Tür | DML |
| WHERE desteği | ✅ Evet |
| Transaction/ROLLBACK | ✅ Geri alınabilir |
| AUTO_INCREMENT sıfırlama | ❌ Hayır |
| Trigger tetikleme | ✅ Evet |
| Foreign key kontrolü | ✅ Evet |
| Hız (büyük tablolar) | 🐢 Yavaş (satır satır) |
| Log | Her satır loglanır |
TRUNCATE — Tablonun Tüm İçeriğini Temizle
TRUNCATE DDL komutudur ve tablodaki tüm satırları bir anda siler. WHERE koşulu kullanılamaz.
Sözdizimi
TRUNCATE TABLE tablo_adi;Kullanım
-- Tüm sipariş kalemlerini temizle
TRUNCATE TABLE order_items;
-- Tüm satırlar anında silindi
-- Log tablosunu temizle
TRUNCATE TABLE activity_logs;TRUNCATE'in Özellikleri
| Özellik | TRUNCATE |
|---|---|
| Tür | DDL |
| WHERE desteği | ❌ Hayır (tüm satırlar silinir) |
| Transaction/ROLLBACK | ❌ Geri alınamaz (auto-commit) |
| AUTO_INCREMENT sıfırlama | ✅ Evet (1'den başlar) |
| Trigger tetikleme | ❌ Hayır |
| Foreign key kontrolü | ✅ Evet (FK varsa hata verebilir) |
| Hız (büyük tablolar) | 🚀 Çok hızlı |
| Log | Minimal (sadece sayfa deallocate) |
TRUNCATE Neden Hızlı?
DELETE FROM tablo her satırı tek tek siler ve her silme işlemini loglar. 10 milyon satırlık bir tabloda bu çok uzun sürer.
TRUNCATE TABLE ise tablonun veri sayfalarını bir bütün olarak serbest bırakır — satırları tek tek silmez. Tablo sanki yeni oluşturulmuş gibi boş hale gelir.
-- 10 milyon satırlık tablo
DELETE FROM huge_table; -- Dakikalar hatta saatler sürebilir
TRUNCATE TABLE huge_table; -- Saniyeler içinde tamamlanırTRUNCATE ve Foreign Key Sorunu
-- Foreign key referansı olan tabloyu TRUNCATE edemezsin
TRUNCATE TABLE customers;
-- ERROR: Cannot truncate a table referenced in a foreign key constraint
-- Çözüm 1: Önce child tabloları temizle
TRUNCATE TABLE order_items;
TRUNCATE TABLE orders;
TRUNCATE TABLE customers; -- Artık çalışır
-- Çözüm 2: Geçici olarak FK kontrolünü kapat
SET FOREIGN_KEY_CHECKS = 0;
TRUNCATE TABLE customers;
SET FOREIGN_KEY_CHECKS = 1;⚠️ Dikkat:
SET FOREIGN_KEY_CHECKS = 0ile FK kontrolünü kapatmak, veri tutarsızlığına yol açabilir. Sadece geliştirme ortamında ve ne yaptığından emin olduğunda kullan. Production'da asla kullanma.
DROP — Tabloyu (veya Veritabanını) Tamamen Yok Et
DROP DDL komutudur ve tablonun yapısıyla birlikte her şeyini siler. Tablo artık yok — sütunlar, veriler, indexler, constraint'ler, hepsi.
Sözdizimi
DROP TABLE tablo_adi;
DROP TABLE IF EXISTS tablo_adi;Kullanım
-- Tabloyu sil
DROP TABLE temp_reports;
-- Güvenli silme (yoksa hata vermez)
DROP TABLE IF EXISTS temp_reports;
-- Birden fazla tabloyu sil
DROP TABLE IF EXISTS temp1, temp2, temp3;
-- Veritabanını sil
DROP DATABASE IF EXISTS test_db;DROP'un Özellikleri
| Özellik | DROP |
|---|---|
| Tür | DDL |
| Ne siler | Tablo yapısı + tüm veriler + indexler + constraint'ler |
| Transaction/ROLLBACK | ❌ Geri alınamaz |
| Sonuç | Tablo artık yok, SHOW TABLES'ta görünmez |
Üçünün Karşılaştırması
Bu tablo en önemli referans noktanız:
| Özellik | DELETE | TRUNCATE | DROP |
|---|---|---|---|
| SQL türü | DML | DDL | DDL |
| Ne siler | Belirli satırları | Tüm satırları | Tablo + tüm veriler |
| WHERE | ✅ Kullanılabilir | ❌ Kullanılamaz | ❌ N/A |
| Tablo yapısı kalır mı | ✅ Evet | ✅ Evet | ❌ Hayır |
| ROLLBACK | ✅ Mümkün | ❌ Mümkün değil | ❌ Mümkün değil |
| AUTO_INCREMENT | Sıfırlanmaz | Sıfırlanır | N/A |
| Trigger tetikler mi | ✅ Evet | ❌ Hayır | ❌ Hayır |
| Hız (büyük tablo) | 🐢 Yavaş | 🚀 Çok hızlı | 🚀 Çok hızlı |
| Disk alanı | Hemen serbest bırakmayabilir | Hemen serbest bırakır | Hemen serbest bırakır |
| FK kontrolü | ✅ Kontrol eder | ✅ Kontrol eder | ✅ Kontrol eder |
Ne Zaman Hangisi?
DELETE kullan:
Belirli satırları silmek istediğinde
Silme işlemini geri alabilmek istediğinde (transaction)
Trigger'ların tetiklenmesi gerektiğinde
Log tablosundaki belirli tarihteki kayıtları temizlerken
-- Kullanım: İptal edilen siparişleri temizle
DELETE FROM orders WHERE status = 'cancelled' AND order_date < '2023-01-01';TRUNCATE kullan:
Tablonun tüm verilerini hızlıca silmek istediğinde
AUTO_INCREMENT'ı sıfırlamak istediğinde
Test/geliştirme ortamında tabloları temizlerken
-- Kullanım: Test verilerini temizle
TRUNCATE TABLE test_orders;DROP kullan:
Tabloya artık hiç ihtiyacın olmadığında
Geçici tabloları temizlerken
Veritabanı yapısını yeniden oluşturacaksan
-- Kullanım: Geçici tabloyu kaldır
DROP TABLE IF EXISTS temp_bestsellers;Soft Delete — Silmeden "Silme"
Gerçek dünyada veri nadiren fiziksel olarak silinir. Bunun yerine soft delete (yumuşak silme) yaklaşımı kullanılır:
-- Fiziksel silme (hard delete) — veri gitti, geri gelmez
DELETE FROM customers WHERE customer_id = 5;
-- Yumuşak silme (soft delete) — veri duruyor ama "silinmiş" işaretleniyor
UPDATE customers
SET is_active = FALSE,
deleted_at = NOW()
WHERE customer_id = 5;Soft delete'in avantajları:
Veri kurtarma mümkün (geri alma =
is_active = TRUEyapma)Yasal gereklilikler karşılanır (bazı veriler yasaya göre silinmemeli)
Audit trail korunur (kim ne zaman sildi?)
Bağlı veriler bozulmaz (foreign key ilişkileri korunur)
-- "Silinmemiş" (aktif) verileri sorgula
SELECT * FROM customers WHERE is_active = TRUE;
-- veya
SELECT * FROM customers WHERE deleted_at IS NULL;
-- "Silinen" kayıtları da dahil et (admin görünümü)
SELECT * FROM customers;💡 İpucu: Çoğu modern uygulama soft delete kullanır. Laravel'de
SoftDeletestrait'i, Django'dais_deletedfield'ı yaygın pattern'lardır. Veritabanı seviyesindeis_activeveyadeleted_atsütunu eklemek yeterlidir.
Gerçek Dünya Örneği — Veri Temizleme Script'i
-- Aylık veri temizleme script'i
-- Her ayın 1'inde çalıştırılır
START TRANSACTION;
-- 1. 6 aydan eski iptal edilmiş siparişlerin kalemlerini sil
DELETE oi FROM order_items oi
JOIN orders o ON oi.order_id = o.order_id
WHERE o.status = 'cancelled'
AND o.order_date < DATE_SUB(NOW(), INTERVAL 6 MONTH);
-- Kaç kayıt silindi?
SELECT ROW_COUNT() AS deleted_items;
-- 2. 6 aydan eski iptal edilmiş siparişleri sil
DELETE FROM orders
WHERE status = 'cancelled'
AND order_date < DATE_SUB(NOW(), INTERVAL 6 MONTH);
SELECT ROW_COUNT() AS deleted_orders;
-- 3. Hiç sipariş vermemiş ve 1 yıldan eski müşterileri pasife al (soft delete)
UPDATE customers
SET is_active = FALSE
WHERE customer_id NOT IN (SELECT DISTINCT customer_id FROM orders)
AND registration_date < DATE_SUB(NOW(), INTERVAL 1 YEAR);
SELECT ROW_COUNT() AS deactivated_customers;
-- Her şey doğru görünüyorsa
COMMIT;Performans Karşılaştırması
10 milyon satırlık bir tabloda:
| İşlem | Yaklaşık Süre | Açıklama |
|---|---|---|
DELETE FROM big_table | 5-30 dakika | Her satır tek tek silinir, loglanır |
DELETE ... WHERE id < 1000000 | 30-120 saniye | 1M satır silinir |
TRUNCATE TABLE big_table | 1-5 saniye | Sayfa bazlı temizleme |
DROP TABLE big_table | <1 saniye | Dosya silme |
DELETE'in yavaş olmasının sebepleri:
Her satır için undo log yazılır (ROLLBACK için)
Her satır için redo log yazılır (crash recovery için)
Index'ler satır bazında güncellenir
Trigger'lar her satır için çalışır
Sıkça Yapılan Hatalar
DELETE ile TRUNCATE'i karıştırmak: "Tabloyu temizle" diyorsun ama DELETE kullanıyorsun — milyonlarca satır tek tek siliniyor ve işlem saatler sürüyor. Tüm tabloyu temizleyeceksen
TRUNCATEkullan.WHERE olmadan DELETE:
DELETE FROM customerstüm müşterileri siler.SQL_SAFE_UPDATES = 1ile bunu engelle.Foreign key sırasını unutmak: Child tabloyu silmeden parent'ı silemezsin. Sıra: önce
order_items, sonraorders, sonracustomers.DROP'u geri alabileceğini sanmak:
DROP TABLEgeri alınamaz. Transaction içinde olsan bile DDL auto-commit yapar.TRUNCATE'in trigger tetiklemediğini bilmemek: Eğer tablodaki silme işlemlerini loglayan bir trigger varsa, TRUNCATE bu trigger'ı çalıştırmaz. Audit kaybı yaşarsın.
Production'da TRUNCATE yerine DROP kullanmak: Tabloyu boşaltmak istiyordun ama DROP ile tabloyu tamamen sildin. Tablonun yapısını tekrar oluşturman gerekir.
Özet
DELETE → DML, belirli satırları siler, WHERE destekler, ROLLBACK yapılabilir, yavaş
TRUNCATE → DDL, tüm satırları siler, WHERE yok, ROLLBACK yok, çok hızlı, AUTO_INCREMENT sıfırlar
DROP → DDL, tabloyu tamamen yok eder (yapı + veri), geri alınamaz
Gerçek uygulamalarda soft delete (is_active = FALSE) tercih edilir
Production'da silme işlemlerinden önce her zaman yedek al
WHERE olmadan DELETE yazmamak için SQL_SAFE_UPDATES modunu aç
Foreign key olan tablolarda silme sırası: child önce, parent sonra
Büyük tablolarda toplu silme için TRUNCATE veya batch DELETE kullan
AI Asistan
Sorularını yanıtlamaya hazır