Orta5 dakikalık okuma

DynamoDB Anahtar Koşulu İfadeleri

Bir anahtar koşulu ifadesi, bir Query'ye geçirdiğiniz KeyConditionExpression'dır — isteğin, DynamoDB'nin item'ları bulmak için kullandığı tek kısmıdır. Geri kalan her şey (filtreler, projeksiyonlar) okuma çoktan ölçüldükten sonra çalışır.

DynamoDB'de anahtar koşulu ifadesi nedir?

Bir anahtar koşulu ifadesi, bir Query üzerindeki KeyConditionExpression'dır ve DynamoDB'ye hangi item'ları okuyacağını söyler. bir eşitlik olmalıdır (PK = :v); tek bir aralık operatörü alır — =, <, <=, >, >=, BETWEEN ya da begins_with. Bir filtreden farklı olarak, neyin okunacağına ve fatura kesileceğine o karar verir.

  • bir eşitlik olmalıdır. Yalnızca PK = :v ve başka bir şey değil — aralık yok, begins_with yok, IN yok. DynamoDB tek bir bölümü bulmak için onu hash'ler.
  • bir aralık operatörü alır. =, <, <=, >, >=, BETWEEN ya da begins_with — bir dilimlediğiniz yer burasıdır.
  • Bir filtre değildir. Bir anahtar koşulu neyin okunacağına ve fatura kesileceğine karar verir; bir FilterExpression yalnızca okuma için ödedikten sonra sonucu kırpar.
  • Sıralama anahtarları bayt sıralıdır. Aralık operatörleri sözlüksel olarak karşılaştırır, bu yüzden sıralama anahtarı string'ini nasıl biçimlendirdiğiniz sizin sorgu gücünüzdür.

Bölüm anahtarı neden eşitliğe kilitli

DynamoDB item'ları, bölüm anahtarını fiziksel bir bölüme hash'leyerek depolar. Bir hash size bir konum verir, bir aralık değil — bu yüzden boyunca taranacak bir şey yoktur.

PK > :v ya da begins_with(PK, :v)'nin doğrudan reddedilmesinin nedeni budur. Motor, tüm tabloyu okumadan "anahtarı X ile başlayan tüm bölümler"i yanıtlayamaz, ki bu tam olarak önlemek için inşa edildiği Scan'dir.

SQL'den geliyorsanız, bu ters hissettirir: WHERE id LIKE 'order%' Postgres'te önemsizdir. DynamoDB'de bölüm anahtarı, aranabilir bir sütun değil, bir adrestir.

Güç sıralama anahtarında yaşar

Bir bölüm içinde item'lar sıralama anahtarına göre sıralı depolanır. O sıralama, aralık operatörlerinin sömürdüğü şeydir — DynamoDB bir konuma arar ve ileri okur.

OperatörOkuduğuNe için kullanılır
SK = :vBir tam itemAnahtarıyla belirli bir çocuk
SK < / <= / > / >= :vAçık uçlu bir dilim"Bu noktadan sonraki her şey"
SK BETWEEN :a AND :bKapalı bir aralık (dahil)Sınırlı bir pencere — bir tarih aralığı
begins_with(SK, :p)Bir önek dilimiPK altında bir tür ya da hiyerarşi

Anahtarda LIKE, CONTAINS, ENDS_WITH yoktur. Alt string ve son ek eşleştirmesi bayt sıralı değildir, bu yüzden tam bir okumaya zorlarlar — tasarım gereği, API buna izin vermez. Alt string eşleştirmesi bir FilterExpression içinde contains() aracılığıyla vardır (okuma için zaten ödediğiniz yerde); son ek eşleştirmesi sunucu tarafında hiç yoktur — tersine çevrilmiş bir anahtar depolayın ya da istemci tarafında filtreleyin. (AWS: Anahtar koşulu ifadeleri)

İşlenmiş bir örnek: bir sohbet uygulamasındaki mesajlar

Diyelim ki kanal tabanlı sohbet inşa ediyorsunuz. Tek tablo, kanala göre bölümlenmiş, mesaj zamanına göre sıralanmış. Orijinal anahtar şeması:

  • Bölüm anahtarı ChannelRefCH#{channelId}
  • Sıralama anahtarı PostedAt — bir ISO-8601 zaman damgası, MSG#2026-06-23T14:05:00Z

MSG# öneki, mesaj satırlarını sıralanabilir ve aynı kanal altında birlikte konumlandırabileceğiniz diğer herhangi bir satır türünden (sabitlenmiş yapılandırma, üyelik) ayrı tutar.

Bir kanalın en son mesajlarını yükleyin. Yalnızca bölüm anahtarı, en yeni önce:

KeyConditionExpression      ChannelRef = :ch
ExpressionAttributeValues   { ":ch": "CH#general" }
ScanIndexForward            false

ScanIndexForward: false, sıralı koleksiyonu ters yönde dolaşır — istemci tarafında sıralamadan "en yeni önce" almanın ucuz yolu.

begins_with ile belirli bir gün. Zaman damgası sıralama anahtarı olduğu ve metin olarak depolandığı için, bir tarih öneki temiz bir dilimdir:

KeyConditionExpression  ChannelRef = :ch AND begins_with(PostedAt, :day)
:ch    "CH#general"
:day   "MSG#2026-06-23"

Bu, 2026-06-23'teki her mesajı ve başka hiçbir şeyi okumaz — DynamoDB öneke arar ve sonundan düştüğünde durur. Bu yalnızca önek, bayt sıralı bir string'in gerçek bir sol sabitlemesi olduğu için çalışır.

BETWEEN ile kesin bir pencere. "14:00 saatindeki mesajlar" için, dahil bir aralık bir öneki yener:

KeyConditionExpression  ChannelRef = :ch AND PostedAt BETWEEN :lo AND :hi
:ch    "CH#general"
:lo    "MSG#2026-06-23T14:00:00Z"
:hi    "MSG#2026-06-23T14:59:59Z"

BETWEEN her iki sınırda da dahildir, bu yüzden uç noktalarınızı bilinçli seçin — buradaki bir birlik-hatası sessizce bir kenar mesajını düşürür ya da ikiye katlar.

Bu ifadelerin herhangi birini, ExpressionAttributeValues haritası sizin için doldurulmuş olarak, DynamoDB expression builder içinde kurup kopyalayabilirsiniz — begins_with ve BETWEEN söz dizimini ilk seferde doğru almak için kullanışlı.

Bu oluşturucu bir pk = … AND begins_with(sk, …) sorgusuna önceden ayarlanmıştır — KeyConditionExpression'ın güncellenmesini görmek için operatörü değiştirin:

İsteğini oluştur
Oluşturulan kod
new QueryCommand({
  "TableName": "AuditLog",
  "KeyConditionExpression": "#hashKey = :hashKeyValue AND begins_with(#rangeKey, :rangeKeyValue)",
  "ExpressionAttributeNames": {
    "#hashKey": "pk",
    "#rangeKey": "sk"
  },
  "ExpressionAttributeValues": {
    ":hashKeyValue": {
      "S": "TENANT#acme"
    },
    ":rangeKeyValue": {
      "S": "EVENT#2026-06"
    }
  }
})

DynoTable'da görüntüleyin

Aynı anahtar koşulunu gerçek bir kanal bölümüne karşı çalıştırın. Bir bölüm anahtarı filtresi ayarladığınız an, DynoTable bir Query yayınlar — böylece tüm koleksiyonu değil, yalnızca o dilimi yüklersiniz.

Tuzak: bir anahtar koşulunu bir filtreyle karıştırmak

Pahalı hata, bir anahtarın işini yapmak için FilterExpression'a uzanmaktır. Bir filtre PostedAt'e bile başvuramaz — o sıralama anahtarıdır ve DynamoDB bir anahtar attribute'unda bir filtreyi bir ValidationException ile reddeder. Bu yüzden geçici çözüm, tarihi düz, anahtar olmayan bir attribute'a (MessageDate) çoğaltmak ve onun üzerinde filtrelemektir:

KeyConditionExpression   ChannelRef = :ch
FilterExpression         begins_with(MessageDate, :day)

Bu, yukarıdaki begins_with anahtar koşuluyla eşdeğer görünür ve aynı satırları döndürür — ama önce tüm kanal bölümünü okur, sonra günün dışındaki her şeyi atar. Tam okuma için fatura kesilirsiniz.

Filtreler okuma maliyetini asla azaltmaz. DynamoDB item'ları ölçtükten sonra çalışırlar, filtreli bir Scan ile aynı ayağa sıkan silah. Bir yüklem anahtar koşuluna gidebiliyorsa, oraya aittir.

Çözüm yukarı akıştadır: bir erişim deseni bir PK eşitliği artı bir sıralama anahtarı aralığı olarak ifade edilemiyorsa, bu bir modelleme sinyalidir. Ya sıralama anahtarını yeniden şekillendirin ya da desen için anahtarlanmış bir dizin ekleyin — anahtarları nasıl yerleştireceğiniz için bkz. GSI ile LSI ve single-table tasarımı.

Tuzaklar ve sonraki adımlar

  • Bölüm anahtarı her zaman ='dir. Asla aralık yok. Bölümler arasında bir aralığa ihtiyacınız varsa, tek bir Query'yi aşmışsınızdır.
  • Sorgu başına bir sıralama anahtarı koşulu. İki sıralama anahtarı yüklemini AND yapamazsınız; BETWEEN ya da begins_with seçin, ikisini birden değil.
  • Ayrılmış sözcükler takma ad gerektirir. Timestamp ya da Name adlı bir anahtar ExpressionAttributeNames (#ts) kullanmalıdır, aksi hâlde sorgu hata verir. (AWS: ayrılmış sözcükler)
  • BETWEEN dahildir. Her iki uç nokta da eşleşir — sınırlarınızı buna göre tasarlayın.

Anahtar koşullarınızı expression builder içinde taslaklayın, sonra onları kendi tablolarınıza karşı çalıştırmak ve her anahtar koşulunun tam olarak hangi dilimi döndürdüğünü görmek için DynoTable'ı deneyin.

Güncellendi