· kaynak dev.to (home feed)
SQLite 3.54, güncelleme indekslenen değeri değiştirmediğinde expression index yeniden yazımını atlıyor
SQLite 3.54, bir UPDATE hesaplanan değeri aynı bıraktığında expression index'leri yeniden yazmayı bıraktı; dev.to'daki bir benchmark, bu tür güncellemelerde %76 daha az WAL sayfası yazıldığını ölçtü.

3.54'te ne değişti
SQLite 3.54.0, 9 Ekim 2026'da yayımlandı; 16 Ekim'de gelen ve alakasız bir 32-bit buffer hatasını düzelten 3.54.1 bunu izledi; bu bilgi dev.to'da yayımlanan el yordamıyla yapılan bir benchmarka dayanıyor. Sürümün değişiklikleri arasında küçük ama hedefli bir yenilik var: expression index'e sahip bir tabloda çalıştırılan bir UPDATE, ifadenin hesapladığı değer aynı kaldığında artık o indeksi yeniden yazmıyor.
Expression index'ler bir sütunun kendisi yerine hesaplanan bir değerin üzerine kurulur; örneğin lower(email) üzerinde bir indeks gibi. 3.54'ten önce, bir satırın e-postasını farklı bir büyük/küçük harf düzeniyle güncelleyen — ve küçük harfli halini değiştirmeyen — bir işlem bile, indeks girdisinin silinip yeniden eklenmesine yol açıyordu.
Ölçülen etki
dev.to benchmarkı, lower(email) üzerinde indeks bulunan 200.000 satırlık bir users tablosu kurdu ve 50.000 satırın kayıtlı e-postalarını büyük harfe çevirdi. lower(email) öncesi ve sonrası aynı olduğundan, sürümler arasındaki tek fark indeks bakım işlemleriydi. Yazılan WAL sayfaları, ifadenin hemen ardından çalıştırılan ve otomatik bir checkpoint sayıyı bulanıklaştırmadan önce sayımı yapan pasif bir checkpoint ile ölçüldü; testler sqlite.org'un önceden derlenmiş Linux CLI derlemelerini kullandı.
3.53.0'ta güncelleme 2.143 WAL sayfası yazdı; 3.54.1'de ise 511 sayfa yazıldı; bu %76'lık bir azalma. Beş çalışmanın en hızlısına göre toplam süre 0,1213 saniyeden 0,0792 saniyeye düştü.
Çarpıcı ayrıntı şu: Aynı güncellemeyi hiç expression index bulunmayan bir tablo kopyasında çalıştırmak da her iki sürümde 511 sayfa yazıyor. Yani 3.54 bu durumda indeks yükünü yalnızca küçültmüyor — tamamen ortadan kaldırıyor ve indekssiz bir tablonun ödeyeceği maliyetle eşitleniyor.
Tablonun tamamı ölçeğinde fark daralıyor. 200.000 satırın tamamını güncellemek 3.53.0'ta 3.779 sayfa, 3.54.1'de 2.148 sayfa yazdı; bu %43'lük bir azalma, çünkü o ölçekte iki sürümün de yazmak zorunda olduğu tablo sayfaları baskın hale geliyor.
Ortaya çıkan veritabanları birebir aynı: Tam bir checkpoint'in ardından her iki dosya da 4.361 sayfayla 17.862.656 bayt çıktı. Tasarruf yalnızca ifadenin çalıştığı sırada yazılan hacimde var, nihai disk boyutunda değil.
Hiçbir işe yaramadığı yer
Benchmark e-postaları gerçekten yeni değerlerle değiştirdiğinde iki sürüm de 2.294 sayfa yazdı — hiçbir fark yok. Zamanlamalar da örtüşüyordu: Beş çalışmada 3.53.0 0,150 ile 0,175 saniye arasında, 3.54.1 ise 0,146 ile 0,219 saniye arasında değişti; yani yeni sürümün yaptığı ek karşılaştırma işi bu ölçekte ölçülebilir bir maliyet olarak görünmüyor.
Düz indekslere yetişme
Sağlanan bu fayda expression index'lere özgü. Bir tam sayı sütunundaki düz bir indekse karşı yapılan kendini atayan (self-assigning) güncelleme hem 3.53.0 hem de 3.54.1'de 133 sayfa yazdı; bu, sıradan sütun indekslerinin zaten gereksiz yeniden yazımları atladığı ve bu sürümün yalnızca açığı kapattığı anlamına geliyor. Her sürümün EXPLAIN çıktısının bytecode'unun karşılaştırılması, 3.54.1'in indeks-ekleme komutunun üzerinden atlayan ek bir IsNull koruması ürettiğini gösteriyor; yazara göre bu atlama tüm mekanizmanın kendisi ve yeniden hesaplanan anahtarın değişmesi gerekmediği durumlarda yürütmenin eklemeyi atlamasını sağlıyor.
Bir belirlilik (determinism) açığı daha var
Benchmark ayrıca SQLite'ın bir indeks ifadesinin içinde neyi kabul ettiğini de test etti. random() üzerinden indeks kurmak iki sürümde de, indeks ifadelerinde belirlenmiş olmayan (non-deterministic) fonksiyonların yasak olduğunu belirten bir hatayla başarısız oluyor; ama datetime('now') her iki sürümde de sorunsuzca kabul ediliyor. Oluşturma zamanındaki kontrol görünüşe göre SQLite'ın fonksiyon tablosunda belirlenmiş olmayan olarak işaretlenmiş fonksiyonları kapsıyor, sonucu saatle değişen her ifadeyi değil. Yazar, SQLite 3.53'ün kayması (drift) yaşayan indeksleri onarmak için REINDEX EXPRESSIONS eklediğini belirtiyor; bu da her kararsız ifadenin en başta yakalanmadığı bir dünyaya uyuyor.
Neden önemli
SQLite tarayıcıların, telefonların ve sayısız sunucunun içinde geliyor; çoğu zaman her ekstra yazılan sayfanın pil ömründen ve cihazın yıpranmasından çaldığı flash depolamada. Yazarken değerleri normalize etmek — bir e-postayı küçük harfe çevirmek, bir alanı yeniden biçimlendirmek, alakasız bir sütun değiştikten sonra satırı yeniden kaydetmek — gündelik bir kalıp ve şimdiye dek tabloda bir expression index varsa bu tür her yazım sessizce bir indeks bakım vergisi ödüyordu. Bu güncellemelerde yazılan sayfalarda %76'lık bir kesinti, gerçek bir yazım amplifikasyonu ve WAL trafiği azaltması; indekslenen değerler gerçekten değiştiğinde ölçülen bir ceza yok ve ortaya çıkan veritabanı dosyasında fark yok. Değişiklik aynı zamanda köklü bir tutumsuzluğu da sessizce ortadan kaldırıyor; expression index'ler artık düz indeksler gibi davranıyor. Geriye kalan uyarı, benchmarkın ortaya çıkardığı o: Sizi duvar saati fonksiyonu üzerinde expression index kurmaktan alıkoyan bir şey yok, o yüzden o particular footgun hâlâ dolu.
- #sqlite
- #databases
- #performance
- #wal
- #storage