İleri7 dakikalık okuma

DynamoDB'de Key Overloading

SQL'den geliyorsanız bir sütun sonsuza dek tek bir şey ifade eder: orders.created_at her zaman bir tarihtir, users.email her zaman bir e-postadır. Key overloading bunu bir kenara atar. Partition ve anahtarlarına genel adlar verirsiniz — pk, sk — ve her item tipinin bunlara farklı bir anlam yüklemesine izin verirsiniz. Tek tablo, birçok varlık, tek bir şekil.

DynamoDB'de key overloading nedir?

Key overloading, birçok varlık tipini tek bir tabloda pk/sk gibi genel anahtar adları altında saklamak, tipi değerde kodlamaktır (USER#u_3001, INVOICE#2026-0014). Attribute adı nötr kalır, böylece senlar, faturalar ve olaylar tek bir partition'ı paylaşır; değer tipi taşır ve bir sort-key öneki, tek bir Query'nin her varlığı begins_with ile dilimlemesine olanak tanır.

  • Genel anahtar adları, tipli değerler. Anahtarlarınızı pk/sk olarak adlandırın ve varlık tipini değere koyun: pk = "TENANT#acme", sk = "USER#u_3001". Ad aptaldır; tipi değer taşır.
  • Single-table tasarımını mümkün kılan şey budur. Overloading olmadan paylaşılan bir tablo yalnızca bir çöp çekmecesidir. Onunla birlikte her varlık, Query çekebileceğiniz bir partition'da oturur.
  • Ödül begins_with'tir. Sort key üzerindeki bir tip öneki, tek bir Query'nin bir varlığın tamamını veya bir dilimini Scan olmadan ve filtre olmadan çekmesini sağlar.
  • Bedeli: okunabilirlik. Ham bir pk/sk dökümü sana hiçbir şey söylemez. Önekleri çözen bir görüntüleyiciye ihtiyacınız var, aksi halde string'lere gözlerinizi kısarak bakarsınız.

Neden genel adlar gerçek adları yener

DynamoDB tablo başına en fazla iki anahtar attribute'u verir ve bir Query yalnızca tek bir partition key'i hedefleyebilir. Yani anahtarınızı userId olarak adlandırırsanız, o tabloda temiz bir şekilde yalnızca kullanıcı item'ları yaşayabilir — geri kalan her şey ya sahte bir userId uydurmak ya da kendi tablosuna taşınmak zorunda kalır.

Overloading bunu aşar. pk gibi nötr bir ad hiçbir varlığa bağlanmaz, böylece bir kullanıcı, bir fatura ve bir denetim olayı aynı anahtar attribute'unu ve aynı tabloyu paylaşabilir. Item'ın ne olduğunu attribute adı değil, değer söyler.

Bu, single-table tasarımını teoriden gerçekten sorgulayabileceğiniz bir şeye dönüştüren hamledir. Paylaşılan tablo kaptır; overloading ise farklı varlıkların onun içinde bir arada var olmasını sağlayan şeydir.

Çok kiracılı bir örnek

Diyelim ki bir SaaS faturalandırma ürünü işletiyorsunuz. Her kiracının üyeleri, faturaları ve bir denetim izi vardır. Üç tablo yerine hepsini bir tabloya koyun ve anahtarları overload edin:

pkskattributes
TENANT#acmeMETAname="Acme Inc", plan="team"
TENANT#acmeUSER#u_3001email, role="admin"
TENANT#acmeUSER#u_3002email, role="member"
TENANT#acmeINVOICE#2026-0014amount_cents, status="paid"
TENANT#acmeINVOICE#2026-0015amount_cents, status="open"
TENANT#acmeEVENT#2026-06-23T09:12Zactor="u_3001", action="invite"

Her satır pk = "TENANT#acme" değerini paylaşır, böylece tek bir oluştururlar — hepsi bir arada bulunur, hepsine tek bir partition okumasıyla erişilebilir.

Partition: TENANT#acmesk: METAsk: USER#u_3001sk: INVOICE#2026-0015sk: EVENT#2026-06-23T09:12ZTek bir Query

Asıl işi sort-key öneki yapıyor. Varlıkları hem gruplar hem de sıralar.

Overload edilmiş koleksiyonu sorgulayın

Tip sort-key önekinde yaşadığı için, begins_with partition'ı hiçbir şeyi taramadan varlığa göre dilimler:

Query pk = "TENANT#acme"  -- the entire tenant, every type
Query pk = "TENANT#acme" AND begins_with(sk, "USER#")  -- just members
Query pk = "TENANT#acme" AND begins_with(sk, "INVOICE#")  -- just invoices

Yalnızca koşulun eşleştiği item'lar için ödeme yaparsınız, partition'ın tamamı için değil — sonra çöpe attığınız satırları okumak için ödeme yaptığınız filtrelenmiş bir Scan işleminin tam tersi. AWS buna anahtar koşulu (condition) der; partition'dan herhangi bir veri çıkmadan önce anahtarlar üzerinde çalışır.

O begins_with koşulunu elle oluşturursanız, tip etiketlerini doğru yazın — USER# yerine sapık bir USERS# sessizce hiçbir şey döndürür. İfade oluşturucu, önekler gerçekten yazdığınızla eşleşsin diye KeyConditionExpression ve ExpressionAttributeValues haritasını üretir.

Index'i de overload edin

Aynı numara bir için de geçerlidir. Ona genel anahtar adları verin — gsi1pk, gsi1sk — ve her varlığın ihtiyaç duyduğu şeyi yazmasına izin verin. Bir index böylece temel tablonun karşılayamayacağı modelleri yanıtlar.

pkskgsi1pkgsi1sk
TENANT#acmeINVOICE#2026-0015STATUS#open2026-06-30
TENANT#acmeINVOICE#2026-0014STATUS#paid2026-06-12
TENANT#betaINVOICE#2026-0099STATUS#open2026-06-25

Artık Query gsi1 WHERE gsi1pk = "STATUS#open", tüm kiracılar genelinde her açık faturayı son ödeme tarihine göre sıralı olarak listeler — temel tablonun kiracı kapsamlı anahtarlarının asla karşılayamayacağı, partition'lar arası bir görünüm. Farklı bir varlık gsi1'i kendi anlamıyla yeniden kullanabilir (örneğin gsi1pk = "ROLE#admin"), böylece tek bir index birkaç okumayı kapsar. Sadece bir GSI'nin nihai tutarlı olduğunu unutmayın — yazmaları temel tablonun gerisinde kalır.

Bunu DynoTable'da yapın

Ham overload edilmiş anahtarlar okumaya düşmandır: INVOICE#2026-0015 ve EVENT#2026-06-23T09:12Z düz bir listede birbirine karışır. Partition'a göre gruplayan ve önekleri öne çıkaran bir görüntüleyici, çöp çekmecesini yeniden varlıklara dönüştürür.

DynoTable, tek bir kiracının item koleksiyonuna göz atarken — META, USER, INVOICE ve EVENT item'ları tek bir overload edilmiş partition key altında gruplanmış.
DynoTable, tek bir kiracının item koleksiyonuna göz atarken — META, USER, INVOICE ve EVENT item'ları tek bir overload edilmiş partition key altında gruplanmış.

Tuzaklar

  • Ayıraçları bir kez seçin ve asla değiştirmeyin. # yerleşik gelenektir. Varlıklar arasında # ile : karıştırmak, hiçbir şeyin sizi uyarmadığı biçimlerde begins_with'i bozar.
  • Aralık matematiği gerektiren değerleri overload etmeyin. INVOICE#2026-0015 şeklindeki bir sort key sözlüksel olarak sıralanır, sayısal olarak değil — string sıralaması kastettiğiniz sırayla eşleşsin diye id'leri ve ISO-8601 tarihlerini kullanın.
  • Önek ad alanını ayırın. İkisi de USER ile başlayan iki varlık tipi (örneğin USER# ve USERGROUP#) begins_with(sk, "USER") altında çakışır. Önekleri ilk karakterden itibaren belirsizlikten uzak tutun.
  • Anahtarlardan önce okumayı planlayın. Overloading, sıraladığınız erişim modellerine hizmet eder. Okumalarınızı henüz bilmiyorsanız, önce single-table tasarımına bakın — anahtarlar sorguların akışında sonraki adımdır.

Bir partition'ın haritasını çıkarın, ardından kendi overload edilmiş anahtarlarınıza göz atmak ve tek bir Query'nin bir kiracının tamamını bir kerede geri getirişini izlemek için DynoTable'ı indirin.

Overload edilmiş bir partition'da sorgu maliyeti

TENANT#acme altındaki her üyeyi begins_with(sk, "USER#") ile listelemek yalnızca kullanıcı satırlarını okur — fatura ya da olayları değil — çünkü anahtar koşulu, veri partition'dan çıkmadan önce filtreler. 200 kullanıcısı (her biri 2 KB) ve 5.000 denetim olayı (her biri 1 KB) olan bir kiracıda bu sorgu ~400 KB'a dokunur (~100 nihai tutarlı RCU). Kullanıcıları bulmak için tablonun tamamında bir Scan, her kiracıdaki her öğeyi ölçümlerdi.

Temsili overload edilmiş öğeleri öğe boyutu hesaplayıcısına yapıştırın, sonra liste sorgularını fiyatlandırma hesaplayıcısında tahmin edin.

Tek tablo aracıyla tasarlayın

Varlıkları (Tenant, User, Invoice, Event) ve erişim desenlerini ("bir kiracının kullanıcılarını listele", "kiracılar arası açık faturalar") tek tablo tasarımı aracına girin. Araç, production'da kullanacağınız overload öneklerine uyan pk/sk şablonları ve GSI anahtarları önerir — siz CloudFormation'a bağlanmadan önce.

Desenlerden sorgu üretin

Önekler sabitlendikten sonra anahtar koşullarını ifade oluşturucuda kurun ve sorgu oluşturucudan sayfalamalı bir program dışa aktarın. Önek yazım hataları (USER# yerine USERS#) hata vermeden boş küme döndürür — üretilmiş ifadeler bu sessiz hata biçimini azaltır.

Varlık tipi önek kaydı

Geliştiricilerin başvurabileceği kısa bir iç tablo tutun:

VarlıkSort önekiÖrnek SKSorgu dilimi
Kiracı metaMETAMETATek öğelik get
KullanıcıUSER#USER#u_3001begins_with(sk, "USER#")
FaturaINVOICE#INVOICE#2026-0015begins_with(sk, "INVOICE#")
OlayEVENT#EVENT#2026-06-23T09:12Zazalan okumayla zaman sıralı kuyruk

Yeni varlık tipleri, mevcut öneklerin begins_with'i altında çakışmayan önekler seçmelidir — dikkatle uzatmadığınız ya da ayıraçla ayırmadığınız sürece USER# ve USERGROUP# ikisi de begins_with(sk, "USER") ile eşleşir.

Güncellendi