MySQL'de CREATE TABLE AS SELECT ile Hızlı Tablo Üretmek

Selamlar, bu yazımda MySQL'in az konuşulan ama gerçekten işe yarayan deyimlerinden birine, CREATE TABLE AS SELECT'e (kısaca CTAS) bakacağız. Konu basit gibi durur: 'bir SELECT yaz, sonucundan tablo üret', tamam. Ama bence asıl mevzu deyimin ne yaptığında değil, ne yapmadığında gizli. Index taşımıyor, primary key kurmuyor, foreign key'i unutuyor. Bunu bilmeden production'a CREATE TABLE ... AS SELECT atan biri ertesi sabah JOIN'lerin neden bu kadar yavaşladığını soruyor olur. Hadi başlayalım.

CTAS nedir, ne işe yarar?

CTAS, tek bir deyim içinde hem yeni bir tablo oluşturur hem de SELECT'in döndürdüğü satırları o tabloya basar. MySQL, sütunların tipini SELECT'in ifadesinden çıkarır (type inference). Yani siz SUM(quantity * unit_price) yazdığınızda, MySQL ortaya çıkan değerin uygun bir decimal(...) olduğuna kendi karar verir.

Korunan şey sadece NOT NULL ve karakter seti gibi sütun-düzeyinde temel attribute'lar. Index'ler, primary key, AUTO_INCREMENT, UNIQUE, foreign key - hiçbiri taşınmaz. Yani CTAS size çıplak bir tablo verir; üzerine ne giydireceğiniz size kalmış.

Tipik kullanım yerleri:

  • Periyodik tazelenen özet (summary) tabloları
  • ETL pipeline'larında geçici staging tabloları
  • Analitik snapshot'lar - 'mart sonu itibarıyla şu durumdaydı' kayıtları

En basit hâli

Önce küçük bir kullanıcı tablosu kuralım, sonra ondan yeni bir tablo türetelim:

CREATE TABLE users (
    id         INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    username   VARCHAR(50)  NOT NULL,
    email      VARCHAR(255) NOT NULL,
    country    CHAR(2),
    created_at DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP
);

INSERT INTO users (username, email, country) VALUES
    ('ali',   'ali@ornek.com',   'TR'),
    ('berk',  'berk@ornek.com',  'TR'),
    ('clara', 'clara@ornek.com', 'DE');

-- TR kullanicilarindan yeni bir tablo turetelim
CREATE TABLE tr_users AS
    SELECT id, username, email, created_at
    FROM users
    WHERE country = 'TR';

Şimdi DESCRIBE tr_users yaparsanız ilginç bir şey görürsünüz: id sütunu var, int unsigned, NOT NULL - hepsi tamam. Ama Key sütunu boş, Extra sütunu boş. Yani primary key yok, AUTO_INCREMENT gitmiş.

Bu yüzden CTAS'ı atar atmaz hemen ardından ALTER TABLE ile eksikleri tamamlamak alışkanlık olmalı:

ALTER TABLE tr_users
    ADD PRIMARY KEY (id),
    ADD UNIQUE INDEX uq_email (email),
    ADD INDEX idx_created_at (created_at);

Hesaplanmış sütunlar ve takma adlar

CTAS'ın gerçek gücü, agregasyon sonuçlarını materialize ederken ortaya çıkıyor. Burada AS ile takma ad vermek şart, çünkü yeni tablonun sütun adı buradan geliyor:

CREATE TABLE order_totals AS
    SELECT
        user_id,
        COUNT(*)                          AS order_count,
        SUM(total_amount)                 AS lifetime_value,
        MIN(created_at)                   AS first_order_at,
        MAX(created_at)                   AS last_order_at
    FROM orders
    GROUP BY user_id;

Takma ad vermezseniz sütun adı COUNT(*) gibi pek de sevimli olmayan bir şey olur ve sonradan refactor canavarı olarak karşınıza çıkar.

Boş bir tablo, sadece yapısı için

Bir tablonun yalnız yapısını kopyalamak istiyorsanız iki yol var. Birincisi CTAS hilesi:

CREATE TABLE users_staging AS
    SELECT * FROM users WHERE 1 = 0;

WHERE 1 = 0 hiçbir satıra uymaz, dolayısıyla tablo boş gelir ama yapısı çıkarılır. Şahsi kanaatim: bu yöntem hızlı bir hile için iyi, ama yine index'siz/PK'sız bir tablo verir. Ben yapısal kopya istediğimde CREATE TABLE ... LIKE tercih ediyorum:

CREATE TABLE users_staging LIKE users;

LIKE versiyonu index'leri ve PK'yı da taşır (FK hariç). Sonra INSERT INTO users_staging SELECT ... FROM users ile veriyi doldurursunuz. Tip sadakati ve index'lerle uğraşmak istemiyorsanız bu çok daha temiz.

CTAS mı, LIKE mı?

İkisi farklı işler için. Karıştırmamak adına kısa bir karşılaştırma:

Özellik CTAS CREATE TABLE LIKE
Veriyi de kopyalar mı? Evet Hayır
Index'leri taşır mı? Hayır Evet
Primary key'i taşır mı? Hayır Evet
Foreign key'i taşır mı? Hayır Hayır
Sütun tipleri Çıkarılır Birebir
İdeal kullanım Özet, snapshot, ETL stage Yapısal kopya

Sık karşılaşılan tuzaklar

  • Primary key eklemeyi unutmak: CTAS sonrası ALTER TABLE ... ADD PRIMARY KEY atmazsanız tablo PK'sız kalır. JOIN'lerde ve replication'da başınız ağrır.
  • AUTO_INCREMENT'in kaybolması: Kaynak tabloda olsa bile yeni tabloya geçmez. Yeni tabloda ihtiyaç varsa elle eklemek lazım.
  • Foreign key beklemek: Foreign key kesinlikle taşınmaz. Referans bütünlüğü gerekiyorsa CTAS sonrası elle tanımlayın.
  • Üretimde uzun süren CTAS: Büyük bir tablodan CTAS atmak metadata lock alır ve kaynak tabloda işlemleri bekletir. Yoğun saatlerde sakın yapmayın; replica üzerinde ya da gece batch'inde tercih edin.
  • Tip çıkarımına güvenmek: Bir decimal(32,2) görürseniz şaşırmayın - MySQL geniş aralık seçer. Sonra ALTER TABLE ... MODIFY ile daraltmak gerekebilir.

Kapanış

Bu yazıda CTAS'ı, ne taşıdığını ve neyi geride bıraktığını gördük. Bence akılda kalması gereken tek cümle şu: CTAS size ham bir tablo verir, geri kalanı sizin işiniz. Periyodik özetler ve hızlı analiz snapshot'ları için biçilmiş kaftan; ama yapısal kopya istiyorsanız CREATE TABLE ... LIKE daha doğru adres. Umarım faydalı olur, bir sonraki yazıda görüşmek üzere.