Firestore Faturası Neden Şişer? Okuma Sayısını Düşürmenin Yolları
Firestore'da "veritabanım küçük, maliyeti de küçüktür" diye düşünmek yanıltıcı. Ücret verinin boyutuna değil, ona kaç kez dokunduğunuza göre hesaplanıyor.
Firestore'un en kolay atlanan tarafı fiyatlandırma modeli. Klasik bir veritabanında maliyeti sunucu belirler; Firestore'da ise fatura büyük ölçüde kaç doküman okuduğunuza göre çıkar.
Bu şu anlama geliyor: 500 dokümanlık minik bir koleksiyonunuz olabilir ama onu her ekran açılışında baştan okuyorsanız, kullanıcı başına günde binlerce okuma üretiyorsunuzdur. Aşağıdakiler, uygulamalarımda karşılaştığım ve düzelttiğim kalıplar.
1. Ekran her açıldığında baştan okumak
En yaygın kalıp bu. Kullanıcı sekmeler arasında gidip geliyor, her dönüşte liste yeniden çekiliyor. Veri değişmemiş olsa bile ücret işliyor.
Çözüm, çevrimdışı önbelleği açık tutmak ve sorguyu önce önbellekten denemek:
// Veri değişmediyse ağa hiç gitme, önbellekten oku
db.collection("gorevler")
.get(GetOptions.CACHE) // önce yerel önbellek
.addOnFailureListener {
db.collection("gorevler").get() // yoksa sunucudan
}
Mobil SDK'larda çevrimdışı kalıcılık zaten varsayılan olarak açık. Ama sorguyu her seferinde sunucudan istemeye zorlarsanız o önbellek hiç kullanılmıyor.
2. Dinleyiciyi kapatmamak
Gerçek zamanlı dinleyiciler (snapshot listener) çok güçlü ama pahalıya
patlayabiliyor. Ekran kapandığında dinleyiciyi durdurmazsanız, kullanıcı uygulamayı
kullanmaya devam ettikçe arka planda okuma üretmeye devam ediyor.
Uygulamayı açıp hiçbir şey yapmadan beş dakika beklediğinizde okuma sayacı artıyorsa
bir dinleyici açık kalmış demektir. Dinleyicileri ekranın yaşam döngüsüne bağlayın
ve kapanışta mutlaka remove() çağırın.
3. Her öğe için ayrı sorgu atmak
Bir liste çekiyorsunuz, sonra listedeki her öğe için ilişkili veriyi ayrı ayrı sorguluyorsunuz. 50 öğelik bir listede bu 1 + 50 = 51 okuma demek.
Firestore'da JOIN olmadığı için buna çözüm veri modelinde: ihtiyaç duyulan
alanı ana dokümana kopyalamak. Buna gömme (denormalizasyon) deniyor ve depolama
maliyetiyle okuma maliyetini takas ediyorsunuz — Firestore'da bu takas neredeyse her
zaman kârlı.
// Her görev için ayrıca kullanıcıyı çekmek yerine
// gösterilecek alanı görevin içine kopyala
{
"baslik": "Rapor hazırla",
"sahipId": "u_1842",
"sahipAdi": "Demir T.", // gömülü kopya
"sahipAvatar": "https://..." // gömülü kopya
}
Kopyalanan alan değiştiğinde güncellemek gerekiyor — bu yüzden yalnızca nadiren değişen ve sık okunan alanları gömmek mantıklı.
4. Sayfalama yapmamak
Koleksiyonun tamamını çekip istemcide filtrelemek, en pahalı ve en yavaş yöntem. Firestore'da okunmayan doküman ücretlendirilmiyor, o yüzden sorguyu daraltmak doğrudan tasarruf demek.
db.collection("gorevler")
.whereEqualTo("durum", "acik") // sunucuda filtrele
.orderBy("tarih", DESCENDING)
.limit(20) // sadece gerekeni al
.get()
Kullanıcı listenin sonuna geldiğinde startAfter() ile bir sonraki sayfayı
çekmek, hem faturayı hem de ilk açılış süresini belirgin şekilde düşürüyor.
5. Saymak için hepsini okumak
"Kaç görev var?" sorusunu cevaplamak için tüm koleksiyonu çekmek, sayı kadar okuma ücreti demek. İki alternatif var:
- Toplama sorgusu:
count()sorgusu, dokümanları tek tek okumaktan çok daha ucuz. - Sayaç alanı: sayıyı ayrı bir dokümanda tutup ekleme/silme sırasında güncellemek. Tek okumayla sayıya ulaşılıyor.
Ölçmeden optimize etmeyin
Firebase konsolundaki kullanım sayfası, okuma/yazma/silme sayılarını günlük olarak gösteriyor. Bir değişiklik yapmadan önce mevcut sayıyı not edin, sonra karşılaştırın.
Ayrıca geliştirme sırasında bütçe uyarısı kurmak iyi bir alışkanlık — yanlışlıkla döngüye giren bir dinleyicinin faturayı ne kadar hızlı büyütebileceğini görmek şaşırtıcı olabiliyor.
Ne zaman Firestore'un kendisi yanlış seçim?
Yukarıdakilerin hepsini uygulamanıza rağmen okuma sayısı hâlâ yüksekse, sorun kullanımda değil veri modelinin şeklinde olabilir. Verisi ilişkisel olan ve karmaşık sorgular gerektiren projelerde bunu ayrı bir yazıda ayrıntılı ele almıştım.
Firestore'da her sorgu bir satın alma. Kodu yazarken "bu çalışıyor mu" kadar "bu kaç okuma ediyor" sorusunu da sormak gerekiyor.
- Firestore
- Firebase
- Maliyet
- Performans
- Mimari
Demir Taşdemir
Mobil Uygulama & Web Geliştirici
2018'den beri yazılım geliştiriyorum. App Store ve Google Play'de 11 uygulama yayınladım; şu an 6 mobil uygulama, 1 e-ticaret platformu ve 1 masaüstü oyun üzerinde çalışıyorum.
Maliyeti de düşünen bir geliştirici
Bir sorgunun ne kadara mal olduğunu bilmek, o sorguyu nasıl yazacağınızı değiştiriyor.