Orta6 dakikalık okuma

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.
  • FilterExpression tuzaktı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).

EvetHayırTemel tablo tüm ürünlerclearanceAt var mı?ClearanceIndex'e kopyalandıİndekste değilİndeksi sorgula = yalnızca tasfiyeöğeleri

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 filtrelerOkuma maliyetini keser mi?Yüklem gücüKurulum maliyeti
Bölüm anahtarıOkumadan önceEvet — tek bölümYalnızca eşitlikBedava (anahtar bu)
Sıralama anahtarıOkumadan önceEvet — bir dilimAralık / begins_withSıralama anahtarı tasarımı
Seyrek indeksOkumadan önceEvet — yalnızca indeksBir niteliğin varlığıEkstra GSI + yazma maliyeti
FilterExpressionOkumadan sonraHayırNeredeyse her koşulYok

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.

Güncellendi