11 puan yazan GN⁺ 2025-12-13 | 2 yorum | WhatsApp'ta paylaş
  • SQLite’in JSON özellikleri kullanılarak ham JSON belgelerini olduğu gibi saklayıp, gerekli alanları sanal üretilmiş sütunlar (virtual generated columns) olarak çıkarıp indeksleme yaklaşımı tanıtılıyor
  • json_extract işleviyle JSON içindeki veriler sütunmuş gibi ele alınabiliyor ve sorgular B-tree indeks hızıyla çalıştırılabiliyor
  • Yeni sorgu desenleri gerektiğinde veri migrasyonu olmadan sütun ve indeks eklenerek genişletilebiliyor
  • Bu yaklaşım, şemasız verinin esnekliğini ve ilişkisel veritabanının performansını aynı anda sağlıyor
  • SQLite kullanan geliştiriciler için sade yapı ve yüksek performans sunan pratik bir desen olarak vurgulanıyor

SQLite ve JSON özelliklerinin birleşimi

  • SQLite, JSON işlevleri ve operatörlerini destekler; bu sayede JSON verisi doğrudan saklanabilir ve işlenebilir
    • JSON belgesini tek bir sütunda olduğu gibi tutup, yalnızca gereken bilgileri sanal sütunlar olarak çıkarabilirsiniz
    • Bu yaklaşım, şema tanımı olmadan veriyi esnek biçimde kullanmayı sağlar
  • DB Pro ekibi son birkaç ayda SQLite’i yoğun biçimde kullanarak bu özellikleri gerçek iş yüklerinde doğruladı
    • SQLite, doğru yapılandırıldığında prodüksiyon ortamında da güvenle kullanılabilir

Sanal üretilmiş sütunlar (Generated Columns)

  • json_extract kullanılarak JSON içindeki belirli değerler sanal üretilmiş sütunlar olarak tanımlanabilir
    • Bu sütunlar gerçek veriyi saklamaz; sorgu anında hesaplanır ve hemen kullanılabilir
    • Ayrı bir backfill süreci ya da veri kopyalama gerekmez
  • Örneğin JSON verisinden belirli alanları çıkarıp onları normal sütunlar gibi ele alan bir yapı kurulabilir

İndeks ekleme ve performans artışı

  • Sanal sütunlara indeks eklendiğinde, JSON verisi de normal sütunlar gibi B-tree indeks hızıyla aranabilir
    • İndeks eklenmiş sanal sütunlar, ilişkisel veritabanı sütunlarıyla aynı performansı sunar
  • Bu yaklaşım, JSON verisinin boyutu büyük olsa bile hızlı aramayı mümkün kılar

Yeni sorgu desenleri ekleme

  • Daha sonra yeni bir alan üzerinden arama gereksinimi doğarsa, yalnızca yeni bir sanal sütun ve indeks eklemek yeterlidir
    • Örnek: user_id alanını çıkarıp buna indeks oluşturmak
    • Mevcut veri satırlarını değiştirmek veya migrasyon yapmak gerekmez
  • Böylece veri yapısını değiştirmeden anında sorgu genişletilebilirliği elde edilir

Desenin avantajları ve önemi

  • Bu desen, şemasız JSON saklamanın esnekliğini ve ilişkisel veritabanı indeks performansını birleştirir
    • İlk tasarım aşamasında indeksleme stratejisini önceden belirlemek gerekmez
    • Gerektiği anda sütunlar ve indeksler eklenerek optimizasyon yapılabilir
  • SQLite kullanan geliştiriciler için basit ama güçlü bir veri işleme yöntemi olarak sunuluyor
  • DB Pro, gelecekte SQLite’in farklı özelliklerini ele alan ek yazılar yayımlayacağını belirtiyor

2 yorum

 
GN⁺ 2025-12-13
Hacker News yorumları
  • JSON belgeleri doğrudan serileştirilmiş bir B-tree olarak kodlanabilir
    Bu sayede iç alanlara indekslenmiş hızlarda doğrudan erişilebilir ve belgenin kendisi zaten indekslenmiş olduğundan ayrıştırma gerekmez
    Bu formata Lite³ deniyor. Üzerinde bizzat çalıştığım bir proje
    GitHub bağlantısı

    • Gerçekten çok havalı! Ben Rkyv'yi seviyorum ama Rust gerektirmesi küçük projelerde yük olabiliyordu
      Lite³'ün lite3_val_bytes ile ikili veri desteği sunması özellikle hoşuma gitti
    • Lite³'ün PostgreSQL'in JSONB yapısından nasıl farklı olduğunu merak ettim
      JSONB, dizi uzunluklarını ve ofsetleri birlikte kodlayarak sıkıştırma verimliliği ile hız arasında denge kurabiliyor
      Lite³ yerinde güncelleme yapabiliyor ama hassas verilerin kalmaması için düzenli olarak “vacuum” gerekiyor
      JSONB yeniden kodlama olmadan güncellenmesi zor bir yapı ama Lite³ yalnızca yapıyı dolaşarak kolayca toparlanabiliyor
      Sıkıştırılabilirlik tarafında JSONB daha iyi olabilir ama Lite³'ün tasarımı bence çok zekice bir yaklaşım
      Ben de bir ASN.1 derleyicisinin bakımını yapıyorum, bu yüzden böyle serileştirme formatlarına ilgim var. Lite³ bana yeni fikirler verdi
    • Rust sürümünde bir uygulama olsa harika olurdu
  • SQLite'ı gerçekten çok seviyorum ama analitik için daha sık DuckDB kullanıyorum
    DuckDB, SQLite gibi tek dosya kullanırken büyük veri kümelerini de son derece hızlı işliyor
    M2 MacBook'ta 20 milyon kaydı işlerken bile çok hızlı
    Örneğin şu sorguyla JSON dosyaları doğrudan okunabiliyor

    SELECT avg(sale_price), count(DISTINCT customer_id)
    FROM '/my-data-lake/sales/2024/*.json';
    

    Ayrıca JSON tipinde kolonlar yükleyip Postgres tarzı col->>'$.key' söz dizimini de kullanabiliyorsunuz

    • İlk sorgunun dosya sistemindeki JSON dosyalarını anında indeksleyip indekslemediğini merak ediyorum
    • DuckDB, görselleştirme aracı pygwalker ile birlikte kullanıldığında yüz binlerce hatta milyonlarca veriyi birkaç saniyede analiz edebiliyor
      Yine de SQLite ile karşılaştırmak biraz haksızlık. SQLite sistem kurmak için, DuckDB ise analitik için daha uygun
      Birden fazla platforma dağıtım yaparken DuckDB biraz zahmetli olabiliyor
    • Veri kümelerini sıkıştırmadan saklamaktan kesinlikle kaçınmak gerekir. DuckDB çeşitli sıkıştırma formatlarını destekliyor
  • JSON performansı için Generated Column kullanmanın yaygın bir yöntem olduğunu sanıyordum
    Postgres'te de JSON kolonundaki anahtarları yabancı anahtar olarak korumak için bunu kullanmıştım. Biraz 'lanetli' bir yöntem ama işe yarıyordu

    • Postgres'te JSONB iç alanlarına doğrudan indeks koymak mümkün değil mi?
      Mesela
      CREATE INDEX idx_status_gin
      ON my_table
      USING gin ((data->'status'));
      
      İlgili blog yazısı
    • Ama böyle durumlarda sonunda anahtar/değer tablosuna ayırmak çoğu zaman daha iyi olabiliyor
      JSON şeması değişirse ayrıştırma ya da migrasyon başarısız olabilir
    • Aslında o kadar da ‘lanetli’ bir yöntem değil. Gereken yerlerde normalize ilişkisel yapı, geri kalan için de jsonb kullanılabilir
    • STORED yerine VIRTUAL kolon kullanılıp kullanılamayacağını merak etmiştim, bu örnek VIRTUAL kullanıyor
  • Bu tekniği yakın zamanda Claude Code'un önerdiği bir optimizasyon örneği sayesinde öğrendim
    SQLite'ın yeni özelliklerini bilmediğim için gözden kaçırmışım ama performans artışı oldukça büyüktü
    Buradan çıkarılacak ders, aşina olduğunuz araçlarda bile belgeleri ara ara yeniden okumanın faydalı olduğudur

    • Kılavuzu yeniden okumak beklenmedik şekilde ufuk açıcı olabiliyor
  • 2023'te HN'de bambax'ın yorumunu görüp bu blog yazısını yazmaya karar vermiştim
    Orijinal yorum bağlantısı

  • JSON'u doğrudan projekte etmeden de indeks oluşturabilirsiniz ama hesaplanmış kolon (computed column) sorguları sadeleştiriyor
    MS-SQL 2025(v17) öncesinde JSON desteği sınırlı olduğu için bu yöntem gerekliydi

    • JSON'u doğrudan sorgulamak yerine yalnızca hesaplanmış kolonları kullanırsanız, yanlışlıkla indekssiz sorgu yazmazsınız
    • Bu özelliği yerel bir DBA konferansında duymuştum ama o zaman bana büyük bir değişiklik gibi gelmemişti
  • HN'de makaleyi açtım ve kendi yorumumun alıntılandığını, üstelik bunun yazının konusu olduğunu görünce tuhaf bir deneyim yaşadım
    “Teşekkürler, bambax!” ifadesini görünce gülümsedim. SQLite gerçekten harika bir araç

  • İlginç ama SQLite'ın "Index On Expression" özelliği de kullanılabilir değil mi?
    Örneğin CREATE INDEX idx_events_type ON events(json_extract(data, '$.type'))
    Ancak JSON path söz dizimi azıcık bile farklı olursa indeks kullanılmayabilir. Buna karşılık Virtual Generated Column her zaman indeksi garanti ediyor

    • İndeks ifadesiyle birlikte view kullanmak, ifade eşleşmesini garanti edebilir
      Örnek: recordlite projesi
    • JSON path yazımı biraz bile değişirse indeks boşa çıkabilir
      Mesela json_extract(data, "$.type") ile data -> '$.type' farklı kabul ediliyor
      Yani WHERE koşulundaki ifade değişirse indeks işe yaramaz hale geliyor
    • Bu basit ve hızlı bir çözüm. Sorgu ile indeksin eşleşmesi gerektiği zaten her zaman geçerli
    • İfade indeksi özelliği, SQLite 3.9.0(2015-10-14) ile gelen görece yeni bir özellik
  • Geliştiricilerin, tutarlı bir şema varken tüm veriyi JSON(B) kolonuna koyma alışkanlığından kaçınmasını isterdim
    İndeks kurmak, kısıtları yönetmek zorlaşıyor ve gerçek kullanımda ek yük artıyor

    • JSON kolonları, ağaç yapısı gibi tablolarla ifade etmesi zor verilerde gerçekten parlıyor
      Mesela Haskell+TypeScript ortamında karmaşık iç içe yapıları JSON olarak serileştirmek çok daha pratik
    • JSON(B), farklı türde verileri tek bir koleksiyonda tutarken faydalı
      Örneğin birden fazla ödeme işlemcisinin sonuçlarını tek tabloda saklamak ya da bir ilan sitesinde kategoriye göre değişen özellikleri yönetmek için
      C# ya da JS/TS'de tür doğrulama araçlarıyla (Zod, OpenAPI vb.) birlikte kullanıldığında yönetimi kolaylaşıyor
    • Basit JSON için normalizasyon daha iyidir ama karmaşık API yanıtlarını tablolara açmak JOIN cehennemine dönüşebilir
      Sonuçta mesele, bakım kolaylığı ile performans arasındaki denge. Bu yazının ana fikri de JSON üzerinde kolayca indeks kurulabilmesi
    • Sensör verilerinde olduğu gibi ağaç yapısının tamamını tek seferde ele almak gereken durumlarda JSON kolonları çok daha basit kalıyor
      Okuma performansı da indekslerle yeterince telafi edilebiliyor
    • Tam normalizasyon çoğu zaman verimsiz olabiliyor
      Örneğin bir ürün fiyatlandırma sisteminde müşteriye özel sıra dışı indirim kurallarını JSON ile ifade etmek çok daha esnek
  • JSON yerine XML kullanırsanız, bu aslında 90'lar ve 2000'lerdeki belge tabanlı veritabanı (document store) modeliyle aynı şey olur
    Ekleme ve güncellemede ayrıştırma yapılıyor, sorgu sırasında ise yalnızca indekse erişiliyordu
    SQLite'ın bunu yerleşik olarak sunması gerçekten çok ilginç

 
iolothebard 2025-12-14
  1. yüzyılın sonunda… universal database diye bir şey vardı… (şimdi doğru ama o zaman yanlıştı.)