Apa cara yang disarankan untuk menghapus sejumlah besar item dari DynamoDB?

111

Saya sedang menulis layanan logging sederhana di DynamoDB.

Saya memiliki tabel log yang dikunci oleh hash user_id dan rentang timestamp (Unix epoch int).

Saat pengguna layanan menghentikan akunnya, saya perlu menghapus semua item dalam tabel, terlepas dari nilai kisarannya.

Apa cara yang disarankan untuk melakukan operasi semacam ini (Ingatlah bahwa mungkin ada jutaan item yang akan dihapus)?

Pilihan saya, sejauh yang saya bisa lihat adalah:

J: Lakukan operasi Pindai, panggil hapus pada setiap item yang dikembalikan, sampai tidak ada item yang tersisa

B: Lakukan operasi BatchGet, sekali lagi panggil delete pada setiap item hingga tidak ada yang tersisa

Keduanya tampak mengerikan bagi saya karena akan memakan waktu lama.

Idealnya apa yang ingin saya lakukan adalah memanggil LogTable.DeleteItem (user_id) - Tanpa memberikan jangkauan, dan membuatnya menghapus semuanya untuk saya.

Tyler
sumber

Jawaban:

52

Idealnya apa yang ingin saya lakukan adalah memanggil LogTable.DeleteItem (user_id) - Tanpa memberikan jangkauan, dan membuatnya menghapus semuanya untuk saya.

Permintaan yang bisa dimengerti memang; Saya dapat membayangkan operasi lanjutan seperti ini mungkin ditambahkan dari waktu ke waktu oleh tim AWS (mereka memiliki riwayat memulai dengan set fitur terbatas terlebih dahulu dan mengevaluasi ekstensi berdasarkan umpan balik pelanggan), tetapi inilah yang harus Anda lakukan untuk menghindari biaya pemindaian penuh setidaknya:

  1. Gunakan Kueri daripada Pindai untuk mengambil semua item user_id- ini berfungsi terlepas dari gabungan kunci utama hash / rentang yang digunakan, karena HashKeyValue dan RangeKeyCondition adalah parameter terpisah dalam API ini dan yang pertama hanya menargetkan nilai Atribut dari komponen hash komposit kunci utama. .

    • Perhatikan bahwa Anda harus menangani paging API kueri di sini seperti biasa, lihat parameter ExclusiveStartKey :

      Kunci utama item untuk melanjutkan kueri sebelumnya. Kueri sebelumnya mungkin memberikan nilai ini sebagai LastEvaluatedKey jika operasi kueri itu terputus sebelum menyelesaikan kueri; baik karena ukuran hasil set atau parameter Batas. LastEvaluatedKey dapat dikirimkan kembali dalam permintaan kueri baru untuk melanjutkan operasi dari titik itu.

  2. Ulangi semua item yang dikembalikan dan fasilitasi DeleteItem seperti biasa

    • Pembaruan : Kemungkinan besar BatchWriteItem lebih sesuai untuk kasus penggunaan seperti ini (lihat di bawah untuk detailnya).

Memperbarui

Seperti yang disorot oleh ivant , operasi BatchWriteItem memungkinkan Anda untuk meletakkan atau menghapus beberapa item di beberapa tabel dalam satu panggilan API [penekanan saya] :

Untuk mengupload satu item, Anda dapat menggunakan PutItem API dan untuk menghapus satu item, Anda dapat menggunakan API DeleteItem. Namun, saat Anda ingin mengunggah atau menghapus data dalam jumlah besar, seperti mengunggah data dalam jumlah besar dari Amazon Elastic MapReduce (EMR) atau memigrasi data dari database lain ke Amazon DynamoDB, API ini menawarkan alternatif yang efisien.

Harap perhatikan bahwa ini masih memiliki beberapa batasan yang relevan, terutama:

  • Operasi maksimum dalam satu permintaan - Anda dapat menentukan total hingga 25 operasi put atau hapus; namun, ukuran permintaan total tidak boleh melebihi 1 MB (muatan HTTP).

  • Bukan operasi atomik - Operasi individual yang ditentukan dalam BatchWriteItem bersifat atomik; namun BatchWriteItem secara keseluruhan adalah operasi "upaya terbaik" dan bukan operasi atom. Artinya, dalam permintaan BatchWriteItem, beberapa operasi mungkin berhasil dan yang lainnya mungkin gagal. [...]

Namun demikian, ini jelas menawarkan keuntungan yang berpotensi signifikan untuk kasus penggunaan seperti yang ada.

Steffen Opel
sumber
4
Saya pikir akan masuk akal untuk menggunakan penghapusan batch untuk langkah kedua (ini "bertopeng" sebagai operasi penulisan batch )
ivant
1
@ivant - terima kasih banyak atas petunjuknya, fungsi penghapusan "bertopeng" dari BatchWriteItem ini benar-benar luput dari saya saat itu; Saya telah memperbarui jawabannya.
Steffen Opel
untuk menghapus dengan BatchWriteItemitem harus ditentukan melaluiTableWriteItems
Neil
1
Tautan ke BatchWriteItem sekarang adalah docs.aws.amazon.com/amazondynamodb/latest/APIReference/…
Tony
3
Saya menyadari ini sudah lama, dan OP tidak menyebutkan SDK bahasa tertentu, tetapi di Python ada level tinggi batch_writer()sebagai bagian dari boto3.resource.TableAPI yang akan "secara otomatis menangani buffering dan mengirim item dalam batch. Selain itu, penulis batch akan juga secara otomatis menangani item yang belum diproses dan mengirimnya kembali sesuai kebutuhan "yaitu pembungkus di sekitar BatchWriteItem yang mengatur bagian-bagian yang mengganggu. boto3.amazonaws.com/v1/documentation/api/latest/reference/…
Davos
46

Menurut dokumentasi DynamoDB Anda cukup menghapus tabel lengkap.

Lihat di bawah:

"Menghapus seluruh tabel secara signifikan lebih efisien daripada menghapus item satu per satu, yang pada dasarnya menggandakan throughput tulis seperti yang Anda lakukan sebanyak operasi penghapusan seperti operasi put"

Jika Anda ingin menghapus hanya sebagian dari data Anda, maka Anda dapat membuat tabel terpisah untuk setiap bulan, tahun atau yang serupa. Dengan cara ini Anda dapat menghapus "bulan lalu" dan menyimpan data Anda yang lain tetap utuh.

Beginilah cara Anda menghapus tabel di Java menggunakan AWS SDK:

DeleteTableRequest deleteTableRequest = new DeleteTableRequest()
  .withTableName(tableName);
DeleteTableResult result = client.deleteTable(deleteTableRequest);
jonathan
sumber
8
Saya suka jawaban ini juga, tetapi hati-hati: ini dapat membuat banyak tabel di sistem Anda dan kami membayar per tabel penyediaan. Jadi, Anda perlu mengurangi penyediaan setelah akhir bulan (jika tabel Anda per bulan) sementara tabel ini tidak dihapus.
Sergio MC Figueiredo
2
setuju dengan jawaban ini, ini diterapkan jika Anda perlu menghapus semua catatan dari tabel, tetapi di sini penanya ingin menghapus entri basis pengguna bukan seluruh tabel.
Ihtsham Minhas
1
Memiliki tabel tabel terpisah untuk setiap pengguna akan mahal mengingat harga DynamoDB. Satu meja per bulan sebenarnya akan memperburuk keadaan. Ini jelas merupakan jawaban untuk masalah yang berbeda dan sangat spesifik.
André Werlang
11
Menghapus tabel juga mungkin bukan pilihan yang menarik jika Anda menggunakan penyediaan otomatis seperti CloudFormation untuk mengelola tabel Anda sebagai bagian dari tumpukan. Saya tidak mengetahui cara sederhana untuk membuat CloudFormation membuat ulang tabel yang Anda hapus secara manual.
brabster
2
Pendekatan ini membutuhkan sedikit waktu untuk menghapus dan membuat ulang tabel (bila diperlukan), sehingga tidak tersedia sepanjang waktu. Pertanyaan tersebut dengan jelas menyatakan penghapusan data pengguna, yang tidak praktis jika dibagi menjadi tabel per pengguna yang terpisah.
André Werlang
13

Jika Anda ingin menghapus item setelah beberapa waktu, misalnya setelah sebulan, gunakan saja opsi Time To Live. Ini tidak akan menghitung unit tulis.

Dalam kasus Anda, saya akan menambahkan ttl saat log kedaluwarsa dan meninggalkannya setelah pengguna dihapus. TTL akan memastikan log pada akhirnya dihapus.

Ketika Time To Live diaktifkan di atas meja, pekerjaan latar belakang memeriksa atribut TTL item untuk melihat apakah kedaluwarsa.

DynamoDB biasanya menghapus item yang kedaluwarsa dalam waktu 48 jam setelah kedaluwarsa. Durasi yang tepat di mana item benar-benar dihapus setelah kedaluwarsa khusus untuk sifat beban kerja dan ukuran tabel. Item yang telah kedaluwarsa dan belum dihapus akan tetap muncul dalam bacaan, kueri, dan pindaian. Item ini masih dapat diperbarui dan pembaruan yang berhasil untuk mengubah atau menghapus atribut kedaluwarsa akan dihormati.

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

Lukas Liesis
sumber
menambahkan TTL adalah "pembaruan" (operasi tulis). Saya tidak yakin ada keuntungan melakukan "update" daripada "menghapus".
Tomer
Anda dapat memasukkan data itu dengan tulisan asli dan diperbarui dengan tindakan pembaruan lainnya. Tentu saja, ini bukan pilihan jika Anda memiliki banyak data dan kemudian Anda ingin menghapusnya. Tetapi ini adalah opsi yang valid untuk kasus di mana Anda dapat memiliki ttl untuk data yang Anda masukkan atau perbarui.
Lukas Liesis
1
Saya setuju, jika sudah ada TTL yang dikonfigurasi dan pembersihan bisa menunggu hingga 48 jam, itu pasti pilihan yang optimal. Mohon maaf jika saya tidak jelas.
Tomer
4

Jawaban dari pertanyaan ini bergantung pada jumlah item dan ukurannya serta anggaran Anda. Tergantung pada 3 kasus berikut:

1- Jumlah item dan ukuran item dalam tabel tidak terlalu banyak. kemudian seperti yang dikatakan Steffen Opel Anda dapat Menggunakan Query daripada Scan untuk mengambil semua item untuk user_id dan kemudian mengulang semua item yang dikembalikan dan memfasilitasiDeleteItem atauBatchWriteItem. Namun perlu diingat Anda mungkin menghabiskan banyak kapasitas throughput di sini. Misalnya, pertimbangkan situasi di mana Anda perlu menghapus 1000 item dari tabel DynamoDB. Asumsikan bahwa setiap item berukuran 1 KB, menghasilkan data sekitar 1MB. Tugas penghapusan massal ini akan membutuhkan total 2000 unit kapasitas tulis untuk melakukan kueri dan penghapusan. Untuk melakukan pemuatan data ini dalam 10 detik (yang bahkan tidak dianggap secepat di beberapa aplikasi), Anda perlu menyetel throughput tulis yang disediakan tabel ke 200 unit kapasitas tulis. Seperti yang Anda lihat, ini bisa dilakukan untuk menggunakan cara ini jika itu untuk jumlah barang yang lebih sedikit atau barang berukuran kecil.

2- Kami memiliki banyak item atau item yang sangat besar di meja dan kami dapat menyimpannya sesuai waktu ke dalam tabel yang berbeda. Kemudian sebagai jonathan Said Anda cukup menghapus tabel. ini jauh lebih baik tetapi saya rasa tidak cocok dengan kasus Anda. Karena Anda ingin menghapus semua data pengguna tidak peduli kapan waktu pembuatan log, jadi dalam hal ini Anda tidak dapat menghapus tabel tertentu. jika Anda ingin memiliki tabel terpisah untuk setiap pengguna maka saya kira jika jumlah pengguna tinggi maka itu sangat mahal dan tidak praktis untuk kasus Anda.

3- Jika Anda memiliki banyak data dan Anda tidak dapat membagi data panas dan dingin Anda ke dalam tabel yang berbeda dan Anda perlu melakukan penghapusan skala besar secara rutin, sayangnya DynamoDB bukanlah pilihan yang baik untuk Anda sama sekali. Mungkin menjadi lebih mahal atau sangat lambat (tergantung pada anggaran Anda). Dalam kasus ini saya merekomendasikan untuk mencari database lain untuk data Anda.

Iman Sedighi
sumber
0

Pendekatan saya untuk menghapus semua baris dari tabel i DynamoDb hanya menarik semua baris keluar dari tabel, menggunakan DynamoDbs ScanAsync dan kemudian memasukkan daftar hasil ke DynamoDbs AddDeleteItems. Kode di bawah ini di C # berfungsi dengan baik untuk saya.

        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();
    }

Catatan: Menghapus tabel dan membuatnya kembali dari konsol web dapat menyebabkan masalah jika menggunakan YAML / CloudFront untuk membuat tabel.

Mohammad
sumber
0

Kami tidak memiliki opsi untuk memotong tabel dinamo. kita harus menjatuhkan tabel dan membuat lagi. Biaya DynamoDB didasarkan pada ReadCapacityUnits & WriteCapacityUnits. Jika kita menghapus semua item menggunakan fungsi BatchWriteItem, itu akan menggunakan WriteCapacityUnits. Jadi lebih baik untuk menghapus record tertentu atau hapus tabel dan mulai lagi.

Shraavan Hebbar
sumber