Generated Column Nedir? Hesaplanan Kolon Mantığı
SQLite'ta generated column, yani hesaplanan kolon, değerini bir INSERT ifadesinden değil, sizin tanımladığınız bir ifadeden alan kolondur. Formülü CREATE TABLE içinde bir kez yazarsınız, gerisini SQLite halleder. Bu kolona elle değer yazamazsınız; denerseniz hata alırsınız.
En sade örnekle başlayalım:
total hiçbir zaman insert edilmedi ama her satırda karşımıza çıkıyor. SQLite, satırı her okuduğunuzda price + tax ifadesinden bu değeri yeniden hesaplıyor. Hangi kolonu güncellerseniz güncelleyin, total da otomatik olarak peşinden geliyor.
GENERATED ALWAYS AS ifadesi zorunlu. Buradaki ALWAYS SQL standardından gelen bir formalite — SQLite'ta zaten başka bir seçenek yok.
VIRTUAL ile STORED arasındaki fark
SQLite'taki her hesaplanan kolon iki türden biri olur. Varsayılan olan VIRTUAL:
Akılda tutulması gereken model:
VIRTUAL— diskte sıfır bayt yer kaplar, ama her okumada CPU harcar. Eklemesi ucuz, sonradan değiştirmesi de ucuz.STORED— disk alanı tüketir, okurken ekstra bir maliyeti yoktur. İfade pahalıysa ya da kolon yazılma sıklığına kıyasla çok daha sık okunuyorsa kendini amorti eder.
Anahtar kelimeyi yazmazsan VIRTUAL alırsınız. Genelde de doğru varsayılan budur.
Neden Kullanalım? İndekslenebilir Türetilmiş Değerler
İşin can alıcı kısmı şu: generated column üzerine indeks koyabilirsiniz. Yani sorgularını baştan yazmana gerek kalmadan türetilmiş değerler üzerinden hızlı arama yapabilirsiniz.
Diyelim ki büyük-küçük harf ayırt etmeden e-posta sorgulamak istiyorsunuz:
İndeks, küçük harfli forma karşılık geliyor. email_lower üzerinden filtreleyen bir sorgu indeksi doğrudan kullanır. SQLite'ın CREATE INDEX ... ON users(lower(email)) gibi ifade indeksleri de var; ama generated column kullandığınızda türetilmiş değer gerçek bir kolon olarak görünür hale geliyor — yani SELECT ile çekebilir, view'lardan referans verebilir ve uygulama kodunda tekrar tekrar kullanabilirsiniz.
JSON İçinden Değer Çekmek
Generated column'lar asıl gücünü JSON ile birlikte gösteriyor. SQLite'ın JSON desteğindeki ->> operatörüyle skaler bir değer çıkarabilirsiniz; bunu bir hesaplanan kolon içine sararsanız, esnek bir blob'un üzerine tipli ve indekslenebilir bir alan eklemiş olursunuz.
user_id ve kind sorgularınız açısından sıradan birer kolon gibi görünür, ama veri aslında payload içinde durur. JSON'u değiştirdiğinizde kolonlar da otomatik güncellenir. user_id üzerindeki indeks sayesinde de arama hızlı olur.
Kurallar ve Kısıtlamalar
SQLite'ın size dayattığı birkaç kural var — duvara toslamadan önce bilmenizde fayda olan şeyler:
- İfade deterministik olmak zorunda.
random(),datetime('now')gibi her çağrıda farklı sonuç döndüren fonksiyonlar kullanılamaz. Değerin, satırdaki verilerden her seferinde aynı şekilde üretilebilmesi gerekir. - İfade yalnızca aynı satırdaki kolonlara referans verebilir. Alt sorgu yok, agregat yok, başka tablolar yok.
- Bir generated column'a doğrudan
INSERTveyaUPDATEyapamazsınız.INSERT INTO products (total) VALUES (5)hata verir. STOREDkolonlarALTER TABLE ... ADD COLUMNile sonradan eklenemez. Tabloya sonradan eklenebilen tek tipVIRTUALkolonlardır.- Generated column'lara
NOT NULL,CHECK,UNIQUEve hattaFOREIGN KEYkısıtlamaları koyabilirsiniz. Bu açıdan diğer kolonlardan farkları yoktur.
Yazma kuralının kısa bir örneği:
sqlite> INSERT INTO products (price, tax, total) VALUES (10, 1, 999);
Runtime error: cannot INSERT into generated column "total"
Çözüm basit: generated kolonu INSERT listesinden çıkarıp hesaplama işini SQLite'a bırakın.
VIRTUAL mı STORED mu? Hangisini seçmeli
Bu seçim genelde okuma/yazma oranınıza ve ifadenin ne kadar maliyetli olduğuna bağlıdır:
Pratik öneriler:
- Varsayılan olarak
VIRTUALkullanın. Yazma anında bedava, ve çoğu senaryo için fazlasıyla yeterli. - Yoğun yazma yapılan bir tabloda kolona indeks koyacaksanız (indeks zaten değerin diskte tutulmasını gerektirir) ya da ifade gerçekten maliyetliyse
STOREDtarafına geçin. - Üstüne fazla kafa yormayın. Tip seçimi şemanın bir parçası ama fikir değiştirirseniz kolonu silip yeniden oluşturabilirsiniz — en azından
VIRTUALiçin bu mümkün.
Generated Column mu, View mu?
View'larla bir miktar örtüşme var: ikisi de hesaplanmış değerleri saklamadan (peki, bazen saklayarak) sunuyor. Ayrım genelde şöyle:
- Generated column tek bir satıra ve tek bir tabloya aittir. Satır bazlı türetmeler için idealdir — bir e-postayı biçimlendirme, JSON alanından veri çıkarma, toplam hesaplama gibi.
- View ise kaydedilmiş bir sorgudur. Birden fazla satırı kapsayan join, aggregation veya filtreleme işine girdiğinizde view kullanın.
İkisini birlikte de kullanabilirsiniz. Bir view, generated column içeren bir tablodan SELECT yapıp ek bağlam için join atabilir. Generated column'lar depolama katmanında durur; view'lar ise sorgu katmanında.
Sırada: ATTACH DATABASE
Generated column'larda bir tablo kendi değerlerini hesaplıyordu. Sonraki sayfada ters yöne gidiyoruz: ATTACH DATABASE ile birden fazla SQLite veritabanını aynı anda bağlayıp tek bir sorgunun farklı dosyalara uzanmasını sağlayacağız.
Sıkça Sorulan Sorular
SQLite'ta generated column nedir?
Generated column, değeri aynı satırdaki diğer kolonlardan türetilen bir ifadeyle hesaplanan kolondur. CREATE TABLE içinde GENERATED ALWAYS AS (ifade) ile tanımlarsınız. Bu kolona doğrudan yazamazsınız — değeri SQLite, satır okunurken ya da yazılırken sizin yerinize hesaplar.
VIRTUAL ve STORED generated column arasındaki fark nedir?
VIRTUAL kolon her okumada yeniden hesaplanır ve diskte yer kaplamaz — varsayılan davranış budur. STORED kolon ise yazma anında bir kez hesaplanıp veritabanı dosyasına yazılır; okumalar ucuzlar, yazmalar bir tık pahalılaşır. İkisi de indekslenebilir ama ifade ağırsa veya kolon yazıldığından çok daha sık okunuyorsa genelde STORED daha mantıklıdır.
SQLite'ta generated column'a indeks koyulabilir mi?
Evet. CREATE INDEX hem VIRTUAL hem de STORED generated column üzerinde çalışır. Zaten bu özelliği kullanmanın en büyük sebebi de budur: lower(email) gibi türetilmiş bir değeri ya da ->> ile çekilmiş bir JSON alanını indeksleyip her sorguyu yeniden yazmadan query planner'ın bu indeksi kullanmasını sağlayabilirsiniz.
ALTER TABLE ile generated column eklenebilir mi?
Eklenebilir, ama yalnızca VIRTUAL için. ALTER TABLE ... ADD COLUMN ... GENERATED ALWAYS AS (...) VIRTUAL sorunsuz çalışır. ALTER TABLE ile STORED generated column eklemek desteklenmiyor — bunun için tabloyu baştan kurmanız gerekir. Yani mevcut tablolara stored kolon eklemek istiyorsanız önceden planlayın.