DynamoDB Filtreleme Stratejileri
DynamoDB'de "filtreleme", aynı kelimeyi giyen dört farklı şey demektir. Üçü veriyi
okunup faturalandırılmadan önce daraltır; biri — Filter adlı olan — onu
sonra daraltır. Hangisinin hangisi olduğunu bilmek, becerinin çoğudur.
DynamoDB'de filtreleme nasıl çalışır?
DynamoDB'de filtrelemenin dört yolu vardır ve yalnızca biri faturalandırıldıktan sonra çalışır. Bölüm anahtarı bir bölümü seçer, sıralama anahtarı bir dilimi daraltır ve seyrek bir indeks nitelik varlığına göre filtreler — üçü de okuma maliyetinizi ölçülmeden önce keser. Bir FilterExpression ise okumadan sonra çalışır, bu yüzden yanıtı küçültür ama faturayı asla.
- Bölüm anahtarı en ucuz filtredir: bölümü seçer, böylece tablonun geri kalanına asla dokunmazsınız.
- Sıralama anahtarı, bir bölümün içinde
begins_with,between,<,>ile filtreler — yine faturalandırmadan önce, yine ucuz. - Seyrek indeks (sparse index) yokluğa göre filtreler: bir öğe yalnızca indekslenmiş niteliğe sahipse indekste görünür, yani indeks filtrelenmiş kümenin kendisidir.
FilterExpressiontuzaktır: DynamoDB okumayı ölçtükten sonra çalışır, bu yüzden yanıt boyutunuzu keser ama faturanızı asla kesmez.
Örneği kurun
Bir ürün kataloğu. Tek tablo, bölüm anahtarı PK, sıralama anahtarı SK:
PK = "DEPT#kitchen" SK = "PROD#00194"
Her ürün ayrıca price, inStock (bir boolean) ve clearanceAt (yalnızca tasfiye
için işaretlenmiş öğelerde bulunan bir unix zaman damgası) taşır. Bir departmandaki
öğeler bir bölümü paylaşır, ürün kimliğine göre sıralanır.
Dört erişim deseni istiyoruz. Her biri farklı bir filtreleme stratejisine eşlenir —
ve herhangi birindeki yanlış seçim, sonsuza dek ödeyeceğiniz bir Scan'dir.
Bölüm anahtarına göre filtreleyin
"Bana kitchen'daki her ürünü ver." Bölüm anahtarı bunu doğrudan yanıtlar:
Query PK = "DEPT#kitchen"
DynamoDB tam olarak bir bölüm okur. Tablodaki başka hiçbir şeye dokunulmaz ya da
faturalandırılmaz. Bu, önemli olan anlamda bedava tek filtredir — Query ile
Scan arasındaki farktır.
SQL'den geliyorsanız bu tersmiş gibi gelir: bir indeksi tarayan bir
WHERE department = 'kitchen' yoktur, sadece bölümü adlandırırsınız. Onu
adlandıramıyorsanız, bu bir sorgu sorunu değil, bir modelleme sorunudur.
Sıralama anahtarına göre filtreleyin
"Bana PROD#00100'dan yukarı mutfak ürünlerini ver." Sıralama anahtarı bölümün
içini daraltır ve bunu okuma ölçülmeden önce yapar:
Query PK = "DEPT#kitchen" AND SK between "PROD#00100" AND "PROD#00200"
Sıralama anahtarı koşulları bilerek sınırlıdır: =, <, <=, >, >=,
between ve begins_with. OR yok, keyfi yüklem yok.
Okumayı hedefli tutan kısıt budur — DynamoDB tüm bölümü değil, bitişik bir dilimi gezer.
Buradaki kol, sıralama anahtarını nasıl kodladığınızdır. Deseniniz "fiyat
bandına göre" ise, bir PROD#<id> sıralama anahtarı yardım etmez — fiyatı anahtara
gömerdiniz.
Bu, sorgu zamanında değil, tasarım zamanında verilen bir sıralama anahtarı stratejisi kararıdır.
Seyrek indekse göre filtreleyin
"Bana şu an tasfiyede olan her şeyi ver." Çoğu ürün değildir, bu yüzden onlardan az olanları bulmak için kataloğu okumak istemezsiniz.
Bir seyrek indeks (sparse index) bunu yoklukla çözer. Bir Global Secondary Index, bir öğeyi yalnızca o öğe indeksin anahtar niteliklerinin her ikisine de sahipse içerir.
GSI bölüm anahtarını clearanceAt'a — yalnızca tasfiye öğelerinde bulunur —
ayarlayın ve indeks başka hiçbir şey tutmasın.
AWS bunu açıkça yazar: bir GSI "yalnızca indekslenmiş niteliklere sahip öğeleri içerir", bu yüzden anahtar niteliği eksik olan öğeler basitçe yayılmaz (AWS — Seyrek indekslerden yararlanın).
Artık sorgu yalnızca tasfiye öğelerini okur, yalnızca onlar için faturalandırılır:
Query ON ClearanceIndex GSI_PK = "CLEARANCE" (clearanceAt'a göre sıralı)
Filtre, veriyi yazdığınızda gerçekleşti — clearanceAt'ı hiç ayarlayıp
ayarlamamayı seçerek. İndeks, filtrelenmiş kümedir. Hangi indeks türünün uyduğu için
bkz. GSI vs LSI.
FilterExpression ile filtreleyin
"Bana stokta olan mutfak ürünlerini ver." inStock bir anahtar niteliği değildir,
bu yüzden bir FilterExpression'a uzanırsınız:
Query PK = "DEPT#kitchen"
Filter inStock = true
İşte tuzak. DynamoDB kitchen bölümündeki her öğeyi okur, hepsi için kapasiteyi
ölçer ve sonra stokta olmayanları atar.
Resmi kural: bir filtre ifadesi "bir Query bittikten sonra ama sonuçlar
döndürülmeden önce uygulanır" ve "herhangi bir ek okuma kapasitesi birimi tüketmez" —
tam okumayı zaten ödediniz
(AWS — Query için filtre ifadeleri).
Yani kitchen'da 10.000 ürün varsa ve 12'si stoktaysa, 10.000 okumak için
ödersiniz. Yanıt küçüktür; fatura değildir. FilterExpression, telden geçen yükü
küçültür, okumayı asla.
İkinci, daha keskin bir kenar daha var: sayfalama filtrelemeden önce ölçülür. Bir sayfa, 1 MB eşleşme değil, 1 MB okunan öğedir.
Bir filtre, ayarlanmış bir LastEvaluatedKey ile boş bir sayfa döndürebilir —
DynamoDB tam bir megabayt okudu, hiçbir şey eşleşmedi, size boş bir dizi verdi.
Sayfalamaya devam edersiniz ve her boş sayfa için ödediniz.
İfadeyi — adlar, değerler ve doğru ayrılmış kelime kaçışı — DynamoDB Expression
Builder ile oluşturun, böylece
#inStock/:val yer tutucuları ilk denemede doğru olsun.
Dördünü karşılaştırın
| Ne zaman filtreler | Okuma maliyetini keser mi? | Yüklem gücü | Kurulum maliyeti | |
|---|---|---|---|---|
| Bölüm anahtarı | Okumadan önce | Evet — tek bölüm | Yalnızca eşitlik | Bedava (anahtar bu) |
| Sıralama anahtarı | Okumadan önce | Evet — bir dilim | Aralık / begins_with | Sıralama anahtarı tasarımı |
| Seyrek indeks | Okumadan önce | Evet — yalnızca indeks | Bir niteliğin varlığı | Ekstra GSI + yazma maliyeti |
| FilterExpression | Okumadan sonra | Hayır | Neredeyse her koşul | Yok |
Tabloyu yukarıdan aşağıya okuyun: yüklem gücü yukarı çıkar, maliyet kontrolü
aşağı iner. FilterExpression her şeyi tam olarak ifade edebilir çünkü zaten
okunmuş öğeler üzerinde çalışır — bu, size para tasarrufu sağlayamamasının da aynı
nedenidir.
DynoTable'da görün
Bir filtreyle bir Query çalıştırdığınızda, okunan öğeler ile döndürülen öğeler
arasındaki fark tüm hikâyedir. DynoTable, sonuç sayısının yanında tüketilen
kapasiteyi yüzeye çıkarır — böylece tüm bölümü sessizce okuyan bir filtre,
aylık faturanızda gizlenmek yerine görünür olur.
Bir filtrenin yanıtlayamayacağı gerçek öğeler-arası sorular için — "departman başına
ortalama fiyat", "stoktaki ürünler incelemeleriyle join'lenmiş" — DynoTable'ın SQL
Workbench'i, tablo geneli bir Scan'e derlemek yerine sınırlı bir sonuç kümesi
üzerinde istemci tarafında GROUP BY, JOIN ve toplamalar çalıştırır.
Tuzaklar ve sonraki adımlar
FilterExpression'ı birincil erişim yolunuz olarak kullanmayın. Bir desen yaygınsa, onu bir anahtara ya da bir seyrek indekse modelleyin. Bir filtre, son küçük daraltma için içindir, çoğunluğu için değil.- Boş sayfalara dikkat edin. Filtreli bir sorgu, uzun süre hiçbir şey
döndürmeden sayfalayabilir.
LastEvaluatedKey'e uyun; boş bir sayfanın "bitti" demek olduğunu varsaymayın. - Bir seyrek indeks bedava değildir. İçine düşen her öğe için yazma kapasitesi ve depolama maliyeti taşır — nitelik nadirken ucuz, değilken daha az ucuz.
Filtreli bir okumanın gerçekte ne kadara mal olacağını kapasite hesaplayıcısı ile tahmin edin ve kendi tablolarınızda tüketilen kapasiteyi döndürülen satırlara karşı izlemek için DynoTable'ı deneyin.