DynamoDB'den çok sayıda öğeyi silmenin önerilen yolu nedir?


112

DynamoDB'de basit bir günlük kaydı hizmeti yazıyorum.

Bir user_id hash ve bir zaman damgası (Unix epoch int) aralığı tarafından anahtarlanmış bir günlükler tablom var.

Hizmetin bir kullanıcısı hesabını sonlandırdığında, aralık değerinden bağımsız olarak tablodaki tüm öğeleri silmem gerekiyor.

Bu tür bir işlemi yapmanın önerilen yolu nedir (Silinecek milyonlarca öğe olabileceğini unutmayın)?

Seçeneklerim, görebildiğim kadarıyla:

A: Hiçbir öğe kalmayana kadar iade edilen her öğe için silme işlevini çağırarak bir Tarama işlemi gerçekleştirin

B: Bir BatchGet işlemi gerçekleştirin, hiçbiri kalmayana kadar her öğe için tekrar delete çağırın

Bunların ikisi de uzun zaman alacağı için bana berbat görünüyor.

İdeal olarak yapmak istediğim şey LogTable.DeleteItem (user_id) - aralığı sağlamadan çağırmak ve benim için her şeyi silmesini sağlamak.

Yanıtlar:


52

İdeal olarak yapmak istediğim şey LogTable.DeleteItem (user_id) - aralığı sağlamadan çağırmak ve benim için her şeyi silmesini sağlamak.

Gerçekten anlaşılabilir bir istek; AWS ekibi tarafından bu gibi gelişmiş işlemlerin zamanla eklenebileceğini hayal edebiliyorum (önce sınırlı bir özellik kümesiyle başlama ve müşteri geri bildirimlerine göre uzantıları değerlendirme geçmişine sahipler), ancak maliyetten kaçınmak için yapmanız gerekenler burada. en azından tam bir tarama:

  1. Tüm öğeleri almak için Tarama yerine Sorguyu kullanın - bu, kullanımdaki birleşik karma / aralık birincil anahtarına bakılmaksızın çalışır, çünkü HashKeyValue ve RangeKeyCondition bu API'deki ayrı parametrelerdir ve birincisi, yalnızca bileşik karma bileşeninin Öznitelik değerini hedefler birincil anahtar. .user_id

    • Lütfen burada sorgu API sayfalama işlemiyle her zamanki gibi ilgilenmeniz gerekeceğini unutmayın, ExclusiveStartKey parametresine bakın:

      Önceki bir sorguya devam edilecek öğenin birincil anahtarı. Daha önceki bir sorgu, bu sorgu işlemi sorguyu tamamlamadan önce kesildiyse, LastEvalutedKey olarak bu değeri sağlayabilir; sonuç kümesi boyutu veya Limit parametresi nedeniyle. LastEvalutedKey, işleme bu noktadan devam etmek için yeni bir sorgu isteğinde geri alınabilir.

  2. İade edilen tüm öğeler üzerinde döngü yapın ve her zamanki gibi DeleteItem'i kolaylaştırın

    • Güncelleme : Büyük olasılıkla BatchWriteItem , bunun gibi bir kullanım durumu için daha uygundur (ayrıntılar için aşağıya bakın).

Güncelleme

İvant'ın vurguladığı gibi , BatchWriteItem işlemi , tek bir API çağrısında [vurgu benim] birden çok tabloya birkaç öğe koymanıza veya silmenize olanak tanır :

Bir öğe yüklemek için PutItem API'sini kullanabilir ve bir öğeyi silmek için DeleteItem API'sini kullanabilirsiniz. Ancak, Amazon Elastic MapReduce'tan (EMR) büyük miktarda veri yüklemek veya başka bir veritabanından Amazon DynamoDB'ye veri taşımak gibi büyük miktarlarda veri yüklemek veya silmek istediğinizde, bu API verimli bir alternatif sunar.

Lütfen bunun hala bazı ilgili sınırlamalara sahip olduğunu unutmayın, en önemlisi:

  • Tek bir istekte maksimum işlem - Toplam 25'e kadar koyma veya silme işlemi belirtebilirsiniz; ancak, toplam istek boyutu 1 MB'ı (HTTP yükü) geçemez.

  • Atomik işlem değil - Bir BatchWriteItem öğesinde belirtilen bağımsız işlemler atomiktir; ancak BatchWriteItem bir bütün olarak bir "en iyi çaba" işlemidir ve atomik bir işlem değildir. Yani, bir BatchWriteItem isteğinde, bazı işlemler başarılı olabilir ve diğerleri başarısız olabilir. [...]

Yine de bu, eldeki gibi kullanım durumları için potansiyel olarak önemli bir kazanç sağlar.


4
İkinci adım için toplu silme kullanmanın mantıklı olacağını düşünüyorum ( toplu yazma işlemi olarak "maskelenmiştir" )
ivant

1
@ivant - ipucu için çok teşekkürler, BatchWriteItem'in bu "maskeli" silme işlevi gerçekten o zamanlar benden kaçtı; Cevabı buna göre güncelledim.
Steffen Opel

BatchWriteItemöğelerle silmek için şu yolla belirtilmesi gerekirTableWriteItems
Neil

1
Tony

4
Bunun eski olduğunun farkındayım ve OP belirli bir dil SDK'sından bahsetmedi, ancak Python'da API'nin bir batch_writer()parçası olarak boto3.resource.Table"arabelleğe almayı ve toplu olarak öğeleri göndermeyi otomatik olarak işleyecek yüksek bir seviye vardır . Ek olarak, toplu yazıcı da ayrıca işlenmemiş öğeleri otomatik olarak işleyin ve gerektiğinde bunları yeniden gönderin "yani can sıkıcı parçaları yöneten BatchWriteItem etrafında bir sarmalayıcıdır. boto3.amazonaws.com/v1/documentation/api/latest/reference/…
Davos

46

DynamoDB belgelerine göre tüm tabloyu silebilirsiniz.

Aşağıya bakınız:

"Bir tablonun tamamını silmek, öğeleri tek tek silmekten önemli ölçüde daha etkilidir; bu, yazma işlemi kadar çok silme işlemi yaptığınız kadar esasen yazma verimini ikiye katlar"

Verilerinizin yalnızca bir alt kümesini silmek isterseniz, her ay, yıl veya benzeri için ayrı tablolar oluşturabilirsiniz. Bu şekilde, "geçen ay" ı kaldırabilir ve verilerinizin geri kalanını olduğu gibi tutabilirsiniz.

AWS SDK'yı kullanarak Java'da bir tabloyu şu şekilde silersiniz:

DeleteTableRequest deleteTableRequest = new DeleteTableRequest()
  .withTableName(tableName);
DeleteTableResult result = client.deleteTable(deleteTableRequest);

8
Ben de bu yanıtı beğendim ama dikkat: Bu, sisteminizde birçok tablo oluşturabilir ve tablo sağlama başına ödeme yaparız. Bu nedenle, ay sonundan sonra (tablonuz aylık ise) bu tablo silinmeden provizyonu azaltmanız gerekir.
Sergio MC Figueiredo

2
bu yanıta katılıyorum, tablodaki tüm kayıtları silmeniz gerekiyorsa uygulanır, ancak burada soru soran kişi tablonun tamamını değil kullanıcı tabanı girişlerini silmek istiyor.
Ihtsham Minhas

1
Her kullanıcı için ayrı bir tabloya sahip olmak, DynamoDB fiyatlandırması göz önüne alındığında pahalı olacaktır. Ayda bir masa aslında işleri daha da kötüleştirir. Bu açıkça farklı, çok özel bir soruna cevaptır.
André Werlang

11
Tablonuzu bir yığının parçası olarak yönetmek için CloudFormation gibi otomatik provizyon kullanıyorsanız, tabloyu silmek de çekici bir seçenek olmayabilir. CloudFormation'ın elle sildiğiniz bir tabloyu yeniden oluşturmasını sağlamanın basit bir yolunu bilmiyorum.
brabster

2
Bu yaklaşım, tabloyu silmek ve yeniden oluşturmak (gerektiğinde) oldukça zaman alır ve tüm zaman boyunca kullanılamaz hale getirir. Soru, kullanıcı verilerinin kaldırılmasını açıkça belirtir ki bu, kullanıcı başına ayrı tablolara bölmek pratik değildir.
André Werlang

14

Bir süre sonra, örneğin bir ay sonra öğeleri silmek isterseniz, Yaşam Süresi seçeneğini kullanın. Bu olacak değil yazma birimleri sayılır.

Sizin durumunuzda, günlüklerin süresi dolduğunda ttl ekler ve bir kullanıcı silindikten sonra bunları bırakırdım. TTL, günlüklerin en sonunda kaldırılmasını sağlar.

Bir tabloda Yaşam Süresi etkinleştirildiğinde, bir arka plan işi, sürelerinin dolup dolmadığını görmek için öğelerin TTL özniteliğini kontrol eder.

DynamoDB genellikle süresi dolan öğeleri son kullanma tarihinden itibaren 48 saat içinde siler. Bir öğenin sona erdikten sonra gerçekten silindiği tam süre, iş yükünün niteliğine ve tablonun boyutuna bağlıdır. Süresi dolan ve silinmeyen öğeler yine de okumalarda, sorgularda ve taramalarda görünecektir. Bu öğeler yine de güncellenebilir ve sona erme özniteliğini değiştirmek veya kaldırmak için başarılı güncellemeler kabul edilecektir.

https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/howitworks-ttl.html


TTL eklemek bir "güncelleme" dir (yazma işlemi). "Silme" yerine "güncelleme" yapmanın herhangi bir kazanımı olduğundan emin değilim.
Tomer

bu verilerin orijinal yazma ile eklenmesini ve başka herhangi bir güncelleme eylemiyle güncellenmesini sağlayabilirsiniz. Elbette, bir sürü veriniz varsa ve sonra onu silmek istiyorsanız, bu bir seçenek değildir. Ancak bu, eklediğiniz veya güncellediğiniz veriler için ttl'ye sahip olabileceğiniz durumlar için geçerli bir seçenektir.
Lukas Liesis

1
Kabul ediyorum, zaten yapılandırılmış TTL varsa ve temizleme 48 saate kadar bekleyebilir, bu kesinlikle en uygun seçenektir. Belirsiz olsaydım özür dilerim.
Tomer

4

Bu sorunun cevabı, öğelerin sayısına, boyutlarına ve bütçenize bağlıdır. Aşağıdaki 3 vakamız olduğuna bağlı:

1- Tablodaki madde sayısı ve ölçüleri çok fazla değil. daha sonra, Steffen Opel'in dediği gibi, user_id için tüm öğeleri almak için Tarama yerine Sorgu Kullanabilir ve ardından iade edilen tüm öğeler üzerinde döngü oluşturabilir ve ya kolaylaştırabilir DeleteItemya daBatchWriteItem. Ancak burada çok fazla üretim kapasitesi harcayabileceğinizi unutmayın. Örneğin, bir DynamoDB tablosundan 1000 öğeyi silmeniz gereken bir durumu düşünün. Her bir öğenin 1 KB boyutunda olduğunu ve yaklaşık 1MB veri elde edildiğini varsayın. Bu toplu silme görevi, sorgulama ve silme için toplam 2000 yazma kapasitesi birimi gerektirecektir. Bu veri yüklemesini 10 saniye içinde gerçekleştirmek için (ki bu bazı uygulamalarda hızlı olarak kabul edilmez), tablonun sağlanan yazma verimini 200 yazma kapasitesi birimine ayarlamanız gerekir. Gördüğünüz gibi, daha az sayıda ürün veya küçük boyutlu ürün için bu şekilde kullanılabilir.

2- Tabloda bir çok eşya veya çok büyük eşyalar var ve bunları zamana göre farklı masalarda saklayabiliyoruz. Daha sonra Jonathan Said olarak tabloyu silebilirsiniz. bu çok daha iyi ama davanızla eşleştiğini sanmıyorum. Günlüklerin oluşturulma zamanı ne olursa olsun tüm kullanıcı verilerini silmek istediğinizden, bu durumda belirli bir tabloyu silemezsiniz. Her kullanıcı için ayrı bir tablo istiyorsanız, o zaman sanırım kullanıcı sayısı yüksekse o zaman çok pahalı ve sizin durumunuz için pratik değil.

3- Çok fazla veriniz varsa ve sıcak ve soğuk verilerinizi farklı tablolara bölemezseniz ve sık sık büyük ölçekli silme işlemi yapmanız gerekiyorsa, maalesef DynamoDB sizin için hiç de iyi bir seçenek değildir. Daha pahalı veya çok yavaş hale gelebilir (bütçenize bağlıdır). Bu durumlarda, verileriniz için başka bir veritabanı bulmanızı tavsiye ederim.


0

DynamoDb i bir tablodan tüm satırları silme yaklaşımım, DynamoDbs ScanAsync kullanarak yalnızca tüm satırları tablodan dışarı çekmek ve ardından sonuç listesini DynamoDbs AddDeleteItems'e beslemek. C # kodunun altındaki kod benim için iyi çalışıyor.

        public async Task DeleteAllReadModelEntitiesInTable()
    {
        List<ReadModelEntity> readModels;

        var conditions = new List<ScanCondition>();
        readModels = await _context.ScanAsync<ReadModelEntity>(conditions).GetRemainingAsync();

        var batchWork = _context.CreateBatchWrite<ReadModelEntity>();
        batchWork.AddDeleteItems(readModels);
        await batchWork.ExecuteAsync();
    }

Not: Tabloyu silmek ve ardından web konsolundan yeniden oluşturmak, tablo oluşturmak için YAML / CloudFront kullanıyorsanız sorunlara neden olabilir.


0

Dinamo tablolarını kesme seçeneğimiz yok. Tabloyu bırakıp yeniden yaratmalıyız. DynamoDB Ücretleri, ReadCapacityUnits & WriteCapacityUnits temel alınarak belirlenir. BatchWriteItem işlevini kullanarak tüm öğeleri silersek, bu WriteCapacityUnits'i kullanacaktır. Bu nedenle, belirli kayıtları silmek veya tabloyu silip yeniden başlamak daha iyidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.