Orta7 dakikalık okuma

DynamoDB'de Bire-Çok İlişkiler

Bir SaaS kontrol düzleminde neredeyse her zaman bir kapsama hiyerarşisi vardır: bir çalışma alanı birçok projeye sahiptir. SQL'de projeler tablosuna bir workspace_id yabancı anahtarı koyar ve JOIN yapardınız.

DynamoDB'de join'ler ve yabancı anahtarlar yoktur, bu yüzden ilişki anahtar şemasının kendisinde yer almak zorundadır. Doğru yapıldığında, "bir çalışma alanını ve içindeki her projeyi yükle" işlemi, bir okuma artı takip eden bir tarama yerine tek bir Query'e dönüşür.

DynamoDB'de bire-çok ilişkiyi nasıl modellersiniz?

Ebeveyne ve tüm alt kayıtlarına aynı verin ki tek bir paylaşsınlar, sonra onları sıralama anahtarıyla birbirinden ayırın. DynamoDB'de join veya yabancı anahtar yoktur, bu yüzden ilişki anahtar şemasının kendisinde yer alır. Bir ebeveyni artı her alt kaydını yüklemek böylece bir join yerine tek bir Query'e dönüşür.

  • Varlıkları değil, okumaları modelleyin. Bire-çok ilişki yalnızca "bir çalışma alanının projelerini listele"ye hizmet etmek için vardır — anahtarları bu sorgunun etrafında şekillendirin.
  • Ebeveyni alt kaydın kodlayın. Çalışma alanına ve tüm projelerine aynı bölüm anahtarı değerini verin ki tek bir düşsünler.
  • Böylece liste okuması tek bir Query'dir. Ebeveyn artı alt kayıtları birlikte geri gelir — join yok, ikinci gidiş-dönüş yok (bir Query sayfa başına 1 MB'a kadar döndürür, bunun ötesinde LastEvaluatedKey ile sayfalayarak).
  • dikkat edin. Tek bir devasa kiracı tüm trafiğini tek bir bölümde yoğunlaştırır; dev bir çalışma alanı, parçalanmış (sharded) bir anahtara ve yayılan (fan-out) bir okumaya ihtiyaç duyabilir.

Önce erişim deseni

DynamoDB modellemesi varlık-öncelikli değil, erişim-deseni-önceliklidir — tek tablo tasarımının ardındaki aynı disiplin. Herhangi bir anahtar seçmeden önce, uygulamanın gerçekten yaptığı okumaları yazın:

  • Bir çalışma alanının ayarlarını getir.
  • Bir çalışma alanındaki her projeyi, en yenisi önce olacak şekilde listele.
  • Belirli bir projeyi kimliğine göre getir.

"Bir çalışma alanı, birçok proje" ilişkisi yalnızca 2 numaralı okuma yüzünden önemlidir. Bir çalışma alanının projelerini birlikte listelemeye asla ihtiyaç duymasaydınız, ilişkiyi hiç modellemezdiniz — projeleri bağımsız olarak saklardınız.

Yani soru asla soyut olarak "bire-çok ilişkiyi nasıl temsil ederim?" değildir. "Bu ilişki hangi sorgulara hizmet etmeli?" sorusudur. Buna cevap verin, sonra anahtarları bunun etrafında şekillendirin.

Bir yabancı anahtar burada neden işe yaramaz

DynamoDB'de her GetItem ve Query bir bölüm anahtarını hedefler ve servis, öğeyi tutan bölümü bulmak için o anahtarı hash'ler.

AWS bunu Temel Bileşenler belgelerinde doğrudan söylüyor: bölüm anahtarı değeri, verinin nerede yaşadığına karar veren dahili bir hash fonksiyonunun girdisidir.

Bu hash tabanlı yerleştirme, tutarlı hashleme ile anahtarların düğümler arasında dağıtıldığı orijinal 2007 tarihli Dynamo: Amazon's Highly Available Key-value Store makalesinden gelen mirastır.

Bir proje öğesindeki çıplak bir workspace_id özniteliği bu mekanizma için görünmezdir — DynamoDB onu "takip" edemez.

İlgili öğeleri tek bir istekte getirmek için, ebeveynin kimliği projenin bölüm anahtarına kodlanmalıdır ki bir çalışma alanının tüm öğeleri aynı bölüme hash'lensin ve tek bir Query onları süpürebilsin.

İşlenmiş örnek: çalışma alanları ve projeler

Genel, aşırı yüklenmiş (overloaded) bir anahtar şeması kullanın. Bölüm anahtarına EntityRef, sıralama anahtarına Detail deyin. Çalışma alanı kimliği, hem çalışma alanı öğesi hem de altındaki her proje için EntityRef'e gider:

EntityRefDetailattributes
WS#acmeMETAdisplayName, region, seatLimit
WS#acmePROJ#2026-0007title, status, createdBy
WS#acmePROJ#2026-0042title, status, createdBy
WS#acmePROJ#2026-0118title, status, createdBy
WS#globexMETAdisplayName, region, seatLimit
WS#globexPROJ#2026-0009title, status, createdBy

Çalışma alanı ve tüm projeleri EntityRef = "WS#acme" değerini paylaşır, bu yüzden tek bir bölümde birlikte yaşayan tek bir öğe koleksiyonu oluştururlar.

Detail sıralama anahtarı onları ayırır: META çalışma alanı kaydıdır ve her proje, projelerin doğal olarak sıralanması için sıfırla doldurulmuş, zaman sıralı bir kimlikle birlikte bir PROJ# öneki taşır.

Görsel olarak, ebeveyn ve alt kayıtları tek bir bölüm içinde, sıralama anahtarına göre sıralanmış olarak istiflenir:

Bölüm: EntityRef = WS#acmeMETA çalışma alanı ayarlarıPROJ#2026-0007PROJ#2026-0042PROJ#2026-0118

EntityRef = "WS#acme" üzerinde tek bir Query, tüm yığını — ebeveyn artı her alt kaydı — tek bir okumada süpürür.

Artık üç erişim deseninin her biri tek bir çağrıya çöker:

  • Çalışma alanı ayarlarıGetItem(EntityRef="WS#acme", Detail="META").
  • Projeleri en yenisi önce listeleDetail begins_with "PROJ#" ile Query(EntityRef="WS#acme"), azalan sırada çalıştırılır (ScanIndexForward = false).
  • Tek bir projeGetItem(EntityRef="WS#acme", Detail="PROJ#2026-0042").

İkincisi işin bütün amacıdır: ebeveyn ve alt kayıtları tek bir Query'den geri gelir, join yok ve ikinci gidiş-dönüş yok — DynamoDB sayfa başına 1 MB'a kadar döndürür ve gerisini getirmeniz için size bir LastEvaluatedKey verir. Bu, bir yabancı anahtar özniteliği ve bir Scan ile yapamayacağınız hamledir.

O begins_with koşulunu elle yazmak zahmetlidir — anahtar-koşul ve yansıtma-ifadesi (projection-expression) sözdizimi zorlar.

DynamoDB İfade Oluşturucu, grameriyle boğuşmayasınız diye KeyConditionExpression'ı, #name/:value yer tutucu eşlemelerini ve çalıştırmaya hazır bir SDK parçacığını üretir:

KeyConditionExpression     "#er = :er AND begins_with(#d, :p)"
ExpressionAttributeNames   { "#er": "EntityRef", "#d": "Detail" }
ExpressionAttributeValues  { ":er": "WS#acme", ":p": "PROJ#" }

Öğe koleksiyonunu DynoTable'da inceleyin

Bu düzenin getirisi görseldir: bir EntityRef'i paylaşan her satır, birbirinin yanında oturan çalışma alanı artı alt kayıtlarıdır.

DynoTable onları gruplar, böylece bire-çok ilişkiyi ayrı tablolar arasında tahmin etmeye çalışmak yerine tek bir bitişik blok olarak görürsünüz.

DynoTable'ın tablo görünümünde tek bir öğe koleksiyonu olarak gruplanmış çalışma alanı META öğesi ve PROJ# alt kayıtları.
DynoTable'ın tablo görünümünde tek bir öğe koleksiyonu olarak gruplanmış çalışma alanı META öğesi ve PROJ# alt kayıtları.

Tuzaklar ve alternatif şekil

Dikkat edilecek birkaç şey:

  • Sıcak bölümler. Bir çalışma alanına ait her öğe tek bir bölümde yaşar, bu yüzden tek bir çok büyük veya çok yoğun kiracı trafiği yoğunlaştırır. AWS'nin tanımladığı uyarlanabilir kapasite davranışı ılımlı çarpıklığı emer, ancak milyonlarca projesi olan bir çalışma alanı parçalanmış bir anahtara (ör. WS#acme#01 … #10) ve yayılan bir okumaya ihtiyaç duyabilir.
  • Öğe koleksiyonu boyutu. Bir yerel ikincil dizinle (LSI), tek bir bölümün öğe koleksiyonu 10 GB ile sınırlıdır; bir LSI olmadan böyle bir sınır yoktur. Burada dizin türlerini tartıyorsanız, GSI ve LSI karşılaştırmasına bakın.
  • Scan'e değil, hep Query'e uzanın. Bütün tasarım, tek bir bölümü Query yapabilesiniz diye vardır. "Bir çalışma alanının projelerini bulmak" için filtrelenmiş bir Scan'e geri dönmek, modeli çöpe atar ve tüm tabloyu okur — Query ve Scan bölümünde ele alınan tuzak.

Projeleri çalışma alanları arası listelemeniz gerçekten gerekiyorsa (diyelim ki küresel olarak tüm status = ACTIVE projeler), temel tablo buna cevap veremez — bölüm anahtarı çalışma alanı kapsamlıdır.

Bu, bu ilişkiyi yeniden şekillendirmenin değil, projeleri farklı bir öznitelik üzerinde yeniden bölümleyen bir ikincil dizinin işidir.

Sonraki adımlar

Erişim desenlerini modelleyin, ebeveyni alt kaydın bölüm anahtarına kodlayın, ve bire-çok okuması tek bir Query olur. Anahtar koşulunu DynamoDB İfade Oluşturucu ile oluşturun ve doğrulayın — erişim desenlerinin kendisinden başlamayı tercih ederseniz, ücretsiz Single-Table Design aracı PK/SK/GSI planını örnek öğelerle birlikte taslaklar.

Sonra bu şemayı yüklemek, çalışma alanı→projeler öğe koleksiyonuna canlı olarak göz atmak ve her sorgunun tam olarak bir okuma yaptığını doğrulamak için DynoTable'ı indirin. Çalışma alanlarını ve projeleri birleştirilmiş, ilişkisel bir görünüm olarak görmeyi tercih ederseniz, DynoTable'ın SQL Workbench'i o JOIN'i de çalıştırır.

Güncellendi

Bu tasarımı etkileşimli olarak dene

Varlıklarını ve erişim desenlerini ücretsiz DynamoDB Single-Table Design aracında taslak olarak oluştur — PK/SK anahtar şablonları önerir, item koleksiyonlarını önizler ve hangi desenlerin GSI gerektirdiğini gösterir.

Single-Table Design aracını aç