DynamoDB Filtreleme Stratejileri
DynamoDB'de "filtreleme", aynı sözcüğü giyen dört farklı şey demektir. Üçü, veriyi
okunmadan ve faturalandırılmadan önce daraltır; biri — Filter adlı olan —
onu sonradan daraltır. Hangisinin hangisi olduğunu bilmek, becerinin çoğudur.
DynamoDB'de filtreleme nasıl çalışır?
DynamoDB'nin filtrelemenin dört yolu vardır ve yalnızca biri faturalandırıldıktan
sonra çalışır. bir partition seçer, sort key bir
dilim daraltır ve bir sparse index öznitelik varlığına göre filtreler — üçü de
okuma maliyetini ölçmeden önce kısar. Bir FilterExpression ise okumadan sonra
çalışır, dolayısıyla yanıtı küçültür ama faturayı asla küçültmez.
- en ucuz filtredir: partition'ı seçer, böylece tablonun geri kalanına asla dokunmazsın.
- , bir partition içinde
begins_with,between,<,>ile filtreler — yine faturalandırmadan önce, yine ucuz. - , yoklukla filtreler: bir öğe, yalnızca indekslenen özniteliğe sahipse index'te görünür, dolayısıyla index, filtrelenmiş kümenin kendisidir.
FilterExpressiontuzaktır: DynamoDB okumayı ölçtükten sonra çalışır, dolayısıyla yanıt boyutunu kısar ama faturanı asla.
Örneği kur
Bir ürün kataloğu. Tek bir tablo, partition key PK, sort key SK:
PK = "DEPT#kitchen" SK = "PROD#00194"
Her ürün ayrıca price, inStock (bir boolean) ve clearanceAt (bir unix zaman
damgası, yalnızca tasfiye için işaretlenmiş öğelerde bulunur) taşır. Bir
departmandaki öğeler bir partition'ı 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 birinde yanlış seçim, sonsuza dek ödeyeceğin bir Scan'dir.
Partition key'e göre filtrele
"kitchen'daki her ürünü ver." Partition key bunu doğrudan yanıtlar:
Query PK = "DEPT#kitchen"
DynamoDB tam olarak bir partition okur. Tablodaki başka hiçbir şeye dokunulmaz veya
faturalandırılmaz. Bu, önemli anlamda bedava olan tek filtredir — Query ile
Scan arasındaki fark.
SQL'den geliyorsan bu tersmiş gibi gelir: bir index'i tarayan bir WHERE department = 'kitchen' yoktur, sen sadece partition'ı adlandırırsın. Onu
adlandıramıyorsan, bu bir sorgu sorunu değil, bir modelleme sorunudur.
Sort key'e göre filtrele
"Bana PROD#00100'den yukarı kitchen ürünlerini ver." Sort key, partition
içini daraltır ve bunu okuma ölçülmeden önce yapar:
Query PK = "DEPT#kitchen" AND SK between "PROD#00100" AND "PROD#00200"
Sort key koşulları bilinçli olarak sınırlıdır: =, <, <=, >, >=,
between ve begins_with. OR yok, rastgele yüklem yok.
O kısıtlama, okumayı hedefli tutan şeydir — DynamoDB tüm partition'ı değil, bitişik bir dilimi yürür.
Buradaki kaldıraç, sort key'i nasıl kodladığındır. Desenin "fiyat aralığına
göre" ise, bir PROD#<id> sort key yardımcı olmaz — fiyatı anahtara gömerdin.
Bu, sorgu zamanında değil, tasarım zamanında verilen bir sort-key stratejisi kararıdır.
Sparse index'e göre filtrele
"Şu anda tasfiyede olan her şeyi ver." Çoğu ürün değil, dolayısıyla az sayıda olanı bulmak için kataloğu okumak istemezsin.
Bir sparse index bunu yoklukla çözer. Bir , yalnızca bir öğe index'in anahtar özniteliklerinin ikisine de sahipse o öğeyi içerir.
GSI partition key'i olarak sabit bir clearance = "CLEARANCE" bayrağı ayarla —
yalnızca tasfiye öğelerine yazılmış — sort key olarak clearanceAt ile ve index
başka hiçbir şey tutmaz.
AWS bunu açıkça belirtir: bir global secondary index yalnızca index'in anahtar özniteliklerine sahip öğeleri içerir, dolayısıyla anahtar özniteliğinden yoksun öğeler basitçe yayılmaz (AWS — Sparse index'lerden yararlanın).
Şimdi sorgu yalnızca tasfiye öğelerini okur, yalnızca onlar için faturalandırılır:
Query ON ClearanceIndex GSI_PK = "CLEARANCE" (sorted by clearanceAt)
Filtre, veriyi yazdığında gerçekleşti — clearanceAt'i hiç ayarlayıp
ayarlamamayı seçerek. Index, filtrelenmiş kümedir. Hangi index türünün uyduğu için
bkz. GSI vs LSI.
FilterExpression ile filtrele
"Bana stokta olan kitchen ürünlerini ver." inStock bir anahtar öznitelik değil,
dolayısıyla bir FilterExpression'a uzanırsın:
Query PK = "DEPT#kitchen"
Filter inStock = true
İşte tuzak. DynamoDB kitchen partition'ındaki her öğeyi okur, hepsi için
kapasiteyi ölçer ve sonra stokta olmayanları düşürür.
AWS şunu belirtir: bir filtre ifadesi, "bir Query bittikten sonra ama sonuçlar
döndürülmeden önce uygulanır" ve "bir Query, bir filtre ifadesi mevcut olup
olmadığına bakılmaksızın aynı miktarda okuma kapasitesi tüketir" — tam okuma için
zaten ödedin (AWS — Query için filtre ifadeleri).
Yani kitchen'da 10.000 ürün varsa ve 12'si stoktaysa, 10.000'i okumaya ödersin.
Yanıt küçük; fatura değil. 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 okunan öğedir, 1 MB eşleşme değil.
Bir filtre, ayarlanmış bir LastEvaluatedKey ile boş bir sayfa döndürebilir —
DynamoDB tam bir megabayt okudu, hiçbir şey eşleşmedi, sana boş bir dizi verdi.
Sayfalamaya devam edersin ve her boş sayfa için ödedin.
İfadeyi — adlar, değerler ve doğru ayrılmış-sözcük kaçışı —
DynamoDB Expression Builder ile oluştur ki
#inStock/:val yer tutucuları ilk seferde doğru olsun.
Aşağıdaki builder, bir FilterExpression içeren bir Scan için önceden
ayarlıdır — yukarıdaki tam anti-desen. Filtrenin bir anahtar dilimi değil, tüm
tablo üzerinde çalıştığına dikkat et:
Dördünü karşılaştır
| Ne zaman filtreler | Okuma maliyetini kısar mı? | Yüklem gücü | Kurma maliyeti | |
|---|---|---|---|---|
| Partition key | Okumadan önce | Evet — bir partition | Yalnızca eşitlik | Bedava (anahtarın kendisi) |
| Sort key | Okumadan önce | Evet — bir dilim | Aralık / begins_with | Sort key tasarımı |
| Sparse index | Okumadan önce | Evet — yalnızca index | Bir özniteliğin varlığı | Ek GSI + yazma maliyeti |
| FilterExpression | Okumadan sonra | Hayır | Neredeyse her koşul | Yok |
Tabloyu yukarıdan aşağıya oku: yüklem gücü yükselir, maliyet kontrolü düşer.
FilterExpression her şeyi tam olarak ifade edebilir, tam da zaten okunmuş öğeler
üzerinde çalıştığı için — sana para kazandıramamasının nedeni de aynı.
DynoTable'da görüntüleyin
Bir filtreyle bir Query çalıştırdığında, okunan öğeler ile döndürülen
öğeler arasındaki boşluk bütün hikayedir. DynoTable, filtreli bir okuma akarken
taranan öğeleri döndürülen öğelerin yanında gösterir — böylece bir partition'ı
sessizce baştan sona okuyan bir filtre, aylık faturanda gizlenmek yerine
görünür olur.
Bir filtrenin yanıtlayamayacağı gerçek öğeler-arası sorular için — "departman
başına ortalama fiyat", "yorumlarına join edilmiş stoktaki ürünler" — DynoTable'ın
SQL Workbench'i, tablo-genişliğinde bir Scan'e derlenmek 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 yolun olarak kullanma. Bir desen yaygınsa, onu bir anahtara veya bir sparse index'e modelle. Bir filtre, son ufak daraltma için, işin çoğu için değil.- Boş sayfalara dikkat et. Filtreli bir sorgu uzun süre hiçbir şey
döndürmeden sayfalayabilir.
LastEvaluatedKey'e uy; boş bir sayfanın "bitti" anlamına geldiğini varsayma. - Bir sparse index bedava değildir. İçine düşen her öğe için yazma kapasitesi ve depolama tutar — öznitelik nadir olduğunda ucuz, olmadığında daha az.
Filtreli bir okumanın gerçekte ne tutacağını fiyatlandırma hesaplayıcısı ile tahmin et ve kendi tablolarında tüketilen kapasiteyi döndürülen satırlara karşı izlemek için DynoTable'ı dene.