Orta5 dakikalık okuma

DynamoDB'de Sıfırla Doldurma (Zero-Padding) Sıralama Anahtarları

Bir DynamoDB dize sıralama anahtarı sözlüksel olarak sıralanır — soldan sağa, her seferinde bir karakter — sayısal olarak değil. Yani "10", "2"den önce gelir, çünkü "1", "2"den önce gelir. Sabit bir genişliğe sıfırla doldurma, dize sırasını sayısal sırayla eşleştirmenin yoludur.

DynamoDB sıralama anahtarında "10" neden "2"den önce sıralanır?

Bir DynamoDB dize sıralama anahtarı, sayısal olarak değil, UTF-8 bayt sırasına göre sözlüksel biçimde karşılaştırılır. "1" baytı "2"den önce geldiğinden "10", "2"den önce sıralanır. Her sayıyı baştaki sıfırlarla sabit bir genişliğe doldurun — "2", "0000000002" olur — ve böylece dize sırası sayısal sırayla tam olarak eşleşir.

  • Tuzak: dize olarak saklanan sayılar kelimeler gibi sıralanır. "100", "11", "2", DynamoDB'nin size verdiği sıradır — kastettiğiniz şey değil.
  • Çözüm: her sayıyı baştaki sıfırlarla sabit bir genişliğe doldurun, böylece "2", "0000000002" olur. Artık sözlüksel ve sayısal sıra uyuşur.
  • Genişliği bir kez seçin: onu saklayacağınız en büyük değer için boyutlandırın, sonra birkaç basamak ekleyin. Genişliği sonradan değiştirmek her anahtarı yeniden yazmak demektir.
  • Azalan bedava: yüksekten düşüğe sıralamak için (liderlik tablosu durumu), maxValue - value saklayın, yine sıfırla doldurulmuş — DynamoDB'nin nitelik başına sıralama yönü yoktur.

Dize sıralama anahtarları neden size ihanet eder

SQL'den geliyorsanız, bir tamsayı sütunu üzerinde ORDER BY score DESC "zaten çalışır" — motor sütunun sayısal olduğunu bilir. DynamoDB'nin, Number türü olmayan bir sıralama anahtarı için böyle bir lüksü yoktur.

DynamoDB, dize (S) sıralama anahtarlarını UTF-8 bayt sırasına göre karşılaştırır, AWS sıralama anahtarı belgelerine göre. Büyüklük değil, baytlar. "9" (0x39), "10"'u geçer çünkü ilk baytı "1"'in (0x31) baytını yener. Uzunluk önemsizdir — yalnızca ilk farklı bayt karar verir.

İşte tuzak: bir sayı bir dize sıralama anahtarının içinde yaşadığı anda, aralığı gezen her Query, karışık görünen bir sırada satır döndürür.

Bir liderlik tablosu sıralama anahtarı oluşturun

Mevsimsel bir atari liderlik tablosu alın. Mevsim başına bir öğe koleksiyonu her oyuncunun koşusunu tutar ve en yüksek skorların önce gelmesini istersiniz.

Onu tek bir öğe koleksiyonunda bir bileşik anahtarla modelleyin:

  • leaderboardId (bölüm anahtarı) — örn. SEASON#2026-SPRING.
  • rankKey (sıralama anahtarı) — sıfırla doldurulmuş skor artı bir eşitlik bozucu (tiebreaker).

Saf bir ilk deneme, ham skoru bir dize olarak saklar:

leaderboardIdrankKeyplayerHandle
SEASON#2026-SPRING"9"quickdraw
SEASON#2026-SPRING"10"ace_pilot
SEASON#2026-SPRING"1500"nightowl
SEASON#2026-SPRING"240"bytecrash

SEASON#2026-SPRING üzerinde bir Query, onları bu bayt sırasında döndürür: "10", "1500", "240", "9". 9 puanlık koşu en sonda oturur ve 1500 puanlık koşu ortada gömülüdür. Bir liderlik tablosu için işe yaramaz.

Sabit bir genişliğe doldurun

Kaydedeceğiniz en büyük skor için yeterince geniş bir genişlik seçin, sonra sıfırla sola doldurun. Diyelim ki skorlar on milyonda sınırlanıyor — bu sekiz basamak, bu yüzden pay için on basamak kullanın:

leaderboardIdrankKeyplayerHandle
SEASON#2026-SPRING"0000000009"quickdraw
SEASON#2026-SPRING"0000000010"ace_pilot
SEASON#2026-SPRING"0000000240"bytecrash
SEASON#2026-SPRING"0000001500"nightowl

Artık her anahtar aynı uzunlukta, bu yüzden bayt-bayt karşılaştırma ve sayısal karşılaştırma aynı sırayı üretir. Artan Query, 9, 10, 240, 1500 verir. Matematik sonunda baytlarla eşleşir.

Genişlik tek yönlü bir kapıdır. On basamağa doldurursanız ve bir skor sonradan onu aşarsa, 11 basamaklı bir değer 10 basamaklı bir değerden önce sıralanır — her şeyi yeniden kırarak — ve bunu düzeltmek her mevcut rankKey'i yeniden yazmak demektir. Genişliği aşırı sağlayın; bedeli bir avuç bayttır.

Azalan sıralama: farkı saklayın

Bir liderlik tablosu en yüksek skoru önce ister. DynamoDB bir sıralama anahtarını ScanIndexForward: false ile ileri ya da geri okuyabilir, bu yüzden azalan genellikle okuma zamanı bir bayraktır — önce ona uzanın.

Ama bir öğe koleksiyonu karışık sıralama yönlerine hizmet etmek zorunda olduğunda ya da okuma bayraklarından bağımsız olarak en yüksek skorun fiziksel olarak önce gelmesini istediğinizde, sayının kendisini ters çevirin. maxValue - score'u, aynı genişliğe sıfırla doldurulmuş olarak saklayın:

score   inverted (9999999999 - score)   rankKey
1500    9999998499                       "9999998499"
240     9999999759                       "9999999759"
10      9999999989                       "9999999989"
9       9999999990                       "9999999990"

Ters çevrilmiş değer üzerinde artan bayt sırası artık orijinal skorları yüksekten düşüğe verir: 1500, 240, 10, 9. Numara, 2007 Amazon Dynamo makalesinin ruhundadır — anahtarlar opak baytlardır, bu yüzden niyeti baytların içine kodlarsınız.

Bir eşitlik bozucu (tiebreaker) ekleyin

İki oyuncu eşitlik yapabilir. Çıplak bir doldurulmuş skor sıralama anahtarında çakışır ve ikinci bir yazma birincinin üzerine yazar (aynı PK + SK). Her koşunun ayrı bir öğe olması ve eşitliklerin belirleyici biçimde çözülmesi için benzersiz bir sonek ekleyin:

rankKey = "<paddedScore>#<paddedTimestamp>#<playerId>"

Örneğin "0000001500#0000001719100800#p_8842". Aynı skor, daha erken zaman damgası daha yüksek slotu kazanır — zaman damgasını da doldurun, yoksa az önce düzelttiğiniz hatayı yeniden ortaya çıkarır.

DynoTable'da sıfırla doldurulmuş rankKey'e göre sıralanan sezon liderlik tablosuna göz atabilir ve doldurulan değerlerin satırları doğru şekilde hizaladığını görebilirsiniz — genişliklerin doğru olduğunun, onları yayınlamadan önceki kanıtıdır.

O bileşik anahtarı elle birleştirdiğinizde bir genişliği yanlış yazmak kolaydır. Bir "mevsimin tepesi" Query'si için KeyConditionExpressionexpression builder içinde üretmek, siz genişliklerle deney yaparken begins_with / between sözdizimini dürüst tutar.

DynoTable'da mevsim liderlik tablosuna göz atma, sıfırla doldurulmuş rankKey'e göre sıralı.
DynoTable'da mevsim liderlik tablosuna göz atma, sıfırla doldurulmuş rankKey'e göre sıralı.

Kaçınılması gereken tuzaklar

  • Çok dar doldurma. Tüm şema, bir değer genişliği aştığı ilk anda çöker. En kötü durum için boyutlandırın, sonra basamak ekleyin.
  • Okuma bayrağını unutmak. Yalnızca azalan okuyorsanız, ScanIndexForward: false tek ihtiyacınız olabilir — bir bayrak işi yaparken ters çevrilmiş anahtarlara uzanmayın.
  • Bir koleksiyonda karışık genişlikler. Bir sıralama aralığını paylaşan her anahtar aynı genişliği kullanmalıdır. Yeni satırları dolduran ama eskileri doldurmayan bir göç, onları yanlış biçimde araya yerleştirir.
  • Yanlış bölümü doldurma. Bir bileşik anahtarda, sıralamaya katılan her sayısal bölümü doldurun — yalnızca skoru değil, hem skoru hem zaman damgasını.

Sonraki adımlar

Sıfırla doldurma, daha geniş sıralama anahtarı tasarımı araç kutusundaki bir araçtır; bir anahtarı birkaç desene hizmet etmek için aşırı yüklediğinizde onu öğe koleksiyonlarıyla eşleştirin ve sıralama doğru olduğunda bir Scan yerine kesin bir Query'ye yaslanın.

Şemayı yayınlamadan önce gerçek bir tabloya göz atmak ve sıfırla doldurulmuş sıralama anahtarlarınızın sayısal sıraya düşmesini izlemek için DynoTable'ı deneyin.

Güncellendi