ALTER TABLE ile Sütun Ekleme, Silme ve Değiştirme
Veritabanı yönetiminde en sık yapılan işlemlerden biri mevcut tabloların yapısını değiştirmektir. Uygulama gereksinimleri değiştikçe, yeni özellikler eklendikçe ya da eski alanlar kullanımdan kalktıkça tabloları güncellemek kaçınılmaz hale gelir. MariaDB ve MySQL’de ALTER TABLE komutu tam da bu iş için tasarlanmıştır ve doğru kullanıldığında oldukça güçlü bir araçtır. Bu yazıda gerçek dünya senaryolarıyla sütun ekleme, silme ve değiştirme işlemlerini tüm detaylarıyla ele alacağız.
ALTER TABLE Nedir ve Neden Önemlidir?
ALTER TABLE, mevcut bir tablonun yapısını değiştirmenize olanak tanıyan DDL (Data Definition Language) komutudur. Tabloya yeni sütun eklemek, var olan sütunu kaldırmak, sütun adını ya da veri tipini değiştirmek, kısıtlamalar eklemek veya kaldırmak gibi onlarca işlemi bu komutla yapabilirsiniz.
Özellikle production ortamında ALTER TABLE çalıştırmak dikkat gerektiren bir operasyondur. Büyük tablolarda bu işlem ciddi bir süre alabilir ve tablo üzerinde kilit oluşturarak diğer sorguları bloke edebilir. Bu yüzden her ALTER TABLE işlemi öncesinde yedeğinizi almış olmak altın kuralınız olsun.
Temel Söz Dizimi
ALTER TABLE komutunun genel yapısı şu şekildedir:
ALTER TABLE tablo_adi
[işlem1],
[işlem2],
...;
Birden fazla değişikliği tek bir ALTER TABLE komutuna ekleyerek tablo üzerindeki kilit süresini minimize edebilirsiniz. Bu özellikle büyük tablolarda kritik bir performans avantajı sağlar.
Sütun Ekleme: ADD COLUMN
Temel Sütun Ekleme
En yaygın kullanım senaryosu tablomuza yeni bir sütun eklemektir. Diyelim ki bir e-ticaret sitesinde urunler tablosuna stok takibi için yeni bir alan eklemeniz gerekiyor:
ALTER TABLE urunler
ADD COLUMN stok_adedi INT NOT NULL DEFAULT 0;
Bu komut stok_adedi adında, varsayılan değeri 0 olan ve NULL olamayan bir tamsayı sütunu ekler. Varsayılan değer vermek önemlidir çünkü mevcut satırlar bu sütun için bir değere ihtiyaç duyacaktır.
Sütunun Konumunu Belirleme
MySQL ve MariaDB’de yeni sütunun tabloda nereye ekleneceğini belirleyebilirsiniz. Bunun için FIRST ve AFTER anahtar kelimeleri kullanılır:
-- Sütunu tablonun en başına ekler
ALTER TABLE musteriler
ADD COLUMN musteri_no VARCHAR(20) FIRST;
-- Belirli bir sütundan sonra ekler
ALTER TABLE musteriler
ADD COLUMN dogum_tarihi DATE AFTER soyad;
Gerçek dünyada bu özelliği çok kullanmasanız da, raporlama araçlarının sütun sıralamasına göre çalıştığı durumlarda işinize yarayabilir.
Birden Fazla Sütun Ekleme
Bir tabloya birden fazla sütun eklemeniz gerektiğinde tek bir ALTER TABLE komutunu tercih edin:
ALTER TABLE siparisler
ADD COLUMN kargo_firmasi VARCHAR(100) AFTER toplam_tutar,
ADD COLUMN kargo_takip_no VARCHAR(50) AFTER kargo_firmasi,
ADD COLUMN kargo_tarihi DATETIME AFTER kargo_takip_no,
ADD COLUMN teslim_tarihi DATETIME AFTER kargo_tarihi;
Bu yöntem, her sütun için ayrı ALTER TABLE çalıştırmak yerine tabloyu tek seferinde kilitler ve işlemi çok daha hızlı tamamlar. Büyük bir tabloda bu fark saatler anlamına gelebilir.
NULL ve DEFAULT Değerler
Sütun eklerken NOT NULL kısıtı koyacaksanız mutlaka bir DEFAULT değer belirtin, aksi takdirde mevcut satırlarda sorun yaşarsınız:
ALTER TABLE kullaniciler
ADD COLUMN son_giris DATETIME DEFAULT NULL,
ADD COLUMN giris_sayisi INT NOT NULL DEFAULT 0,
ADD COLUMN aktif TINYINT(1) NOT NULL DEFAULT 1;
Sütun Silme: DROP COLUMN
Basit Sütun Silme
Artık kullanılmayan bir sütunu tablodan kaldırmak için DROP COLUMN kullanılır:
ALTER TABLE kullaniciler
DROP COLUMN eski_sistem_id;
Uyarı: Sütun silme işlemi geri alınamaz ve o sütundaki tüm veriler kalıcı olarak silinir. Bu işlem öncesinde mutlaka yedek alın ya da en azından silinecek veriyi başka bir tabloya taşıyın.
Bağımlılıkları Kontrol Etme
Bir sütunu silmeden önce üzerinde index, foreign key ya da başka kısıtlar olup olmadığını kontrol etmelisiniz. Önce tabloyu inceleyelim:
-- Tablo yapısını görüntüle
SHOW CREATE TABLE siparislerG
-- Indexleri listele
SHOW INDEX FROM siparisler;
-- Foreign key kısıtlarını kontrol et
SELECT
CONSTRAINT_NAME,
COLUMN_NAME,
REFERENCED_TABLE_NAME,
REFERENCED_COLUMN_NAME
FROM information_schema.KEY_COLUMN_USAGE
WHERE TABLE_NAME = 'siparisler'
AND TABLE_SCHEMA = 'eticaret_db'
AND REFERENCED_TABLE_NAME IS NOT NULL;
Eğer sütun üzerinde bir foreign key varsa önce onu kaldırmanız gerekir:
-- Önce foreign key kısıtını kaldır
ALTER TABLE siparisler
DROP FOREIGN KEY fk_musteri_id;
-- Sonra sütunu silebilirsin
ALTER TABLE siparisler
DROP COLUMN eski_musteri_ref;
Birden Fazla Sütunu Aynı Anda Silme
ALTER TABLE log_kayitlari
DROP COLUMN debug_bilgisi,
DROP COLUMN test_verisi,
DROP COLUMN gecici_flag;
Sütun Değiştirme: MODIFY ve CHANGE
MariaDB/MySQL’de sütun değiştirmek için iki farklı komut bulunur ve aralarındaki farkı anlamak önemlidir.
MODIFY COLUMN ile Veri Tipi Değiştirme
MODIFY COLUMN, sütun adını değiştirmeden veri tipini veya kısıtlarını değiştirmek için kullanılır:
-- VARCHAR alanını genişlet
ALTER TABLE urunler
MODIFY COLUMN aciklama TEXT;
-- INT alanını BIGINT'e yükselt
ALTER TABLE siparisler
MODIFY COLUMN siparis_id BIGINT NOT NULL AUTO_INCREMENT;
-- VARCHAR boyutunu artır
ALTER TABLE musteriler
MODIFY COLUMN telefon VARCHAR(20) NOT NULL;
Gerçek dünya senaryosu: Bir müşteri yönetim sisteminde notlar alanı başlangıçta VARCHAR(255) olarak tanımlandı. Zamanla kullanıcıların daha uzun notlar girmesi gerekti ve alan kısıt oluşturmaya başladı. Bu durumda:
-- Önce mevcut durumu kontrol et
SELECT MAX(LENGTH(notlar)) as max_uzunluk,
COUNT(*) as toplam_kayit
FROM musteriler
WHERE notlar IS NOT NULL;
-- Gerekiyorsa TEXT tipine dönüştür
ALTER TABLE musteriler
MODIFY COLUMN notlar TEXT DEFAULT NULL;
CHANGE COLUMN ile Sütun Adını Değiştirme
CHANGE COLUMN hem adı hem de veri tipini aynı anda değiştirebilir. Sütun adını değiştirirken bile veri tipini tekrar belirtmek zorundasınız:
-- Sütun adını değiştir (veri tipi aynı kalıyor)
ALTER TABLE urunler
CHANGE COLUMN fiyat birim_fiyat DECIMAL(10,2) NOT NULL;
-- Hem adı hem tipi değiştir
ALTER TABLE kullaniciler
CHANGE COLUMN kullanici_adi username VARCHAR(100) NOT NULL UNIQUE;
MariaDB 10.5+ ile RENAME COLUMN
MariaDB 10.5 sürümünden itibaren sadece sütun adını değiştirmek için daha temiz bir syntax mevcuttur:
ALTER TABLE musteriler
RENAME COLUMN ad TO first_name,
RENAME COLUMN soyad TO last_name;
Bu yaklaşım CHANGE COLUMN‘a göre daha güvenlidir çünkü veri tipini yanlışlıkla değiştirme riski yoktur.
Veri Tipi Dönüşümlerinde Dikkat Edilmesi Gerekenler
Veri tipini değiştirirken var olan verilerin yeni tiple uyumlu olup olmadığını kontrol etmek kritik öneme sahiptir.
-- Önce potansiyel sorunları tespit et
-- VARCHAR'dan INT'e geçmeden önce sayısal olmayan değerleri bul
SELECT id, telefon
FROM musteriler
WHERE telefon REGEXP '[^0-9]';
-- DECIMAL hassasiyetini değiştirmeden önce veri kaybı riski
SELECT birim_fiyat,
ROUND(birim_fiyat, 1) as yuvarlanmis,
birim_fiyat - ROUND(birim_fiyat, 1) as fark
FROM urunler
WHERE ABS(birim_fiyat - ROUND(birim_fiyat, 1)) > 0
LIMIT 20;
Büyük ve hassas sistemlerde veri tipi dönüşümü için önerilen yaklaşım şöyledir:
-- 1. Yeni sütunu ekle
ALTER TABLE siparisler
ADD COLUMN yeni_tutar DECIMAL(15,4) DEFAULT NULL;
-- 2. Veriyi dönüştürerek kopyala
UPDATE siparisler
SET yeni_tutar = CAST(eski_tutar AS DECIMAL(15,4));
-- 3. Doğrulama yap
SELECT COUNT(*) FROM siparisler WHERE yeni_tutar IS NULL;
SELECT COUNT(*) FROM siparisler WHERE ABS(yeni_tutar - eski_tutar) > 0.001;
-- 4. Eski sütunu kaldır, yeniyi yeniden adlandır
ALTER TABLE siparisler
DROP COLUMN eski_tutar,
CHANGE COLUMN yeni_tutar tutar DECIMAL(15,4) NOT NULL DEFAULT 0;
Index ve Kısıt Yönetimi
ALTER TABLE ile index ve kısıt da ekleyip kaldırabilirsiniz.
Index Ekleme ve Silme
-- Tekil index ekle
ALTER TABLE kullaniciler
ADD INDEX idx_email (email);
-- Birleşik index ekle
ALTER TABLE siparisler
ADD INDEX idx_musteri_tarih (musteri_id, siparis_tarihi);
-- Unique index ekle
ALTER TABLE urunler
ADD UNIQUE INDEX idx_urun_kodu (urun_kodu);
-- Full-text index ekle (MyISAM veya InnoDB)
ALTER TABLE blog_yazilari
ADD FULLTEXT INDEX ft_icerik (baslik, icerik);
-- Index sil
ALTER TABLE kullaniciler
DROP INDEX idx_eski_index;
Foreign Key Ekleme
ALTER TABLE siparisler
ADD CONSTRAINT fk_siparisler_musteri
FOREIGN KEY (musteri_id)
REFERENCES musteriler(id)
ON DELETE RESTRICT
ON UPDATE CASCADE;
Büyük Tablolarda ALTER TABLE Stratejileri
Production ortamında milyonlarca satır içeren tablolarda ALTER TABLE çalıştırmak ciddi risk taşır. Bu durumda birkaç farklı strateji uygulanabilir.
pt-online-schema-change Kullanımı
Percona Toolkit’in pt-online-schema-change aracı, tabloyu kilitlemeden değişiklik yapmanızı sağlar:
# pt-osc ile sütun ekleme (tablo kilitlenmeden)
pt-online-schema-change
--alter "ADD COLUMN yeni_alan VARCHAR(100) DEFAULT NULL"
--host=localhost
--user=root
--ask-pass
--execute
D=veritabani_adi,t=buyuk_tablo
# Dry run ile önce test et
pt-online-schema-change
--alter "MODIFY COLUMN aciklama TEXT"
--host=localhost
--user=root
--ask-pass
--dry-run
D=eticaret,t=urunler
gh-ost Kullanımı
GitHub’ın geliştirdiği gh-ost de online schema değişikliği için popüler bir araçtır:
gh-ost
--user="root"
--password="sifre"
--host=localhost
--database="eticaret"
--table="siparisler"
--alter="ADD COLUMN kargo_ucreti DECIMAL(8,2) DEFAULT 0"
--execute
Manuel Shadow Tablo Yöntemi
Araç kullanmak istemiyorsanız ya da ortamınız izin vermiyorsa manuel yöntemi deneyebilirsiniz:
-- 1. Yeni yapıyla boş bir shadow tablo oluştur
CREATE TABLE siparisler_yeni LIKE siparisler;
-- 2. Shadow tabloya yeni sütunu ekle
ALTER TABLE siparisler_yeni
ADD COLUMN kargo_ucreti DECIMAL(8,2) NOT NULL DEFAULT 0;
-- 3. Veriyi toplu kopyala (batch halinde)
INSERT INTO siparisler_yeni
SELECT *, 0 as kargo_ucreti
FROM siparisler
LIMIT 10000;
-- 4. Tabloları değiştir
RENAME TABLE siparisler TO siparisler_eski,
siparisler_yeni TO siparisler;
-- 5. Doğrulamadan sonra eski tabloyu sil
DROP TABLE siparisler_eski;
Pratik Senaryo: E-Ticaret Veritabanı Migrasyonu
Gerçek bir senaryo üzerinden gidelim. Bir e-ticaret sitesine KVKK uyumu için yeni alanlar eklemeniz, eski bazı alanları yeniden adlandırmanız ve kullanımdan kalkmış alanları kaldırmanız gerekiyor:
-- Transaction içinde yap (DDL implicit commit'e dikkat, bu örnek yapısal gösterim)
-- Önce backup al
-- mysqldump -u root -p eticaret musteriler > musteriler_backup.sql
-- Tek seferde tüm değişiklikleri uygula
ALTER TABLE musteriler
-- KVKK için yeni alanlar
ADD COLUMN kvkk_onay TINYINT(1) NOT NULL DEFAULT 0 AFTER email,
ADD COLUMN kvkk_onay_tarihi DATETIME DEFAULT NULL AFTER kvkk_onay,
ADD COLUMN veri_silme_talebi TINYINT(1) NOT NULL DEFAULT 0,
ADD COLUMN veri_silme_tarihi DATETIME DEFAULT NULL,
-- Eski alanı yeniden adlandır
CHANGE COLUMN tc_kimlik kimlik_hash VARCHAR(64) DEFAULT NULL,
-- Gereksiz alanı kaldır
DROP COLUMN eski_crm_id,
-- Sütun tipini büyüt
MODIFY COLUMN adres TEXT DEFAULT NULL,
-- Yeni index ekle
ADD INDEX idx_kvkk_onay (kvkk_onay),
ADD INDEX idx_veri_silme (veri_silme_talebi);
-- Değişiklikleri doğrula
DESCRIBE musteriler;
SHOW INDEX FROM musteriler;
Sık Yapılan Hatalar ve Çözümleri
Hata 1: Row size too large
InnoDB’de bir satırın maksimum boyutu 65535 byte’ı geçemez. Çok fazla sütun ya da büyük VARCHAR alanları bu hataya yol açabilir:
-- Satır boyutunu tahmin et
SELECT
COLUMN_NAME,
DATA_TYPE,
CHARACTER_MAXIMUM_LENGTH,
NUMERIC_PRECISION
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'veritabani'
AND TABLE_NAME = 'tablo_adi'
ORDER BY ORDINAL_POSITION;
Hata 2: Cannot add foreign key constraint
Foreign key eklerken referans verilen sütunun aynı veri tipine ve ilgili index’e sahip olması gerekir:
-- Referans tablodaki index varlığını kontrol et
SHOW INDEX FROM referans_tablo;
-- Veri tiplerinin eşleştiğini kontrol et
SELECT COLUMN_NAME, DATA_TYPE, COLUMN_TYPE
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = 'db_adi'
AND TABLE_NAME IN ('ana_tablo', 'referans_tablo')
AND COLUMN_NAME IN ('musteri_id', 'id');
Hata 3: Specified key was too long
Index için kullanılan sütunun boyutu fazla olduğunda karşılaşılan bir hatadır:
-- Prefix index kullan
ALTER TABLE musteriler
ADD INDEX idx_email (email(100));
-- Ya da innodb_large_prefix aktifse
SET GLOBAL innodb_large_prefix = ON;
ALTER TABLE Öncesi Kontrol Listesi
Herhangi bir ALTER TABLE işlemi yapmadan önce şu adımları takip etmeyi alışkanlık haline getirin:
- Yedek al:
mysqldumpya da snapshot ile mutlaka yedek alın - Test ortamında dene: Production’a uygulamadan önce aynı veri hacmiyle test edin
- Süreyi tahmin et:
ALTER TABLEişleminin ne kadar süreceğini tahmin edin, gerekirse maintenance window planlayın - Bağımlılıkları kontrol et: Silinecek ya da değiştirilecek sütunu kullanan view, stored procedure, trigger ve uygulama kodlarını listeleyin
- Yük durumunu değerlendir: Mümkünse işlemi düşük trafik saatlerinde yapın
- Rollback planı hazırla: İşlem başarısız olursa nasıl geri döneceğinizi önceden belirleyin
Sonuç
ALTER TABLE komutu veritabanı yönetiminin temel taşlarından biridir ve doğru kullanıldığında büyük esneklik sağlar. Ancak özellikle production ortamlarında bu komutu çalıştırmak dikkat, planlama ve hazırlık gerektirir. Küçük tablolarda sorunsuz çalışan bir işlem, milyonlarca satır içeren tablolarda ciddi sorunlara yol açabilir.
Günlük kullanımda şu pratik özeti aklınızda tutun: Sütun eklerken DEFAULT değer belirleyin, birden fazla değişikliği tek komutta birleştirin, büyük tablolarda pt-osc ya da gh-ost gibi araçları değerlendirin ve her şeyden önce yedek almayı ihmal etmeyin. Veritabanı yönetimi sabır ve titizlik isteyen bir iştir; acele verilen kararlar veri kaybına ya da uzun downtime sürelerine neden olabilir.
