วิธีที่แนะนำในการลบรายการจำนวนมากจาก DynamoDB คืออะไร?


111

ฉันกำลังเขียนบริการบันทึกอย่างง่ายใน DynamoDB

ฉันมีตารางบันทึกที่คีย์โดยแฮช user_id และช่วงเวลา (Unix epoch int)

เมื่อผู้ใช้บริการยุติบัญชีของตนฉันจำเป็นต้องลบรายการทั้งหมดในตารางโดยไม่คำนึงถึงค่าช่วง

วิธีที่แนะนำในการดำเนินการประเภทนี้คืออะไร (โปรดทราบว่าอาจมีรายการหลายล้านรายการให้ลบ)

ตัวเลือกของฉันเท่าที่ฉันเห็นคือ:

ตอบ: ดำเนินการสแกนโดยเรียกลบรายการที่ส่งคืนแต่ละรายการจนกว่าจะไม่เหลือรายการใด ๆ

B: ดำเนินการ BatchGet อีกครั้งเรียกลบในแต่ละรายการจนกว่าจะไม่มีเหลือ

ทั้งสองอย่างนี้ดูแย่สำหรับฉันเพราะจะใช้เวลานาน

สิ่งที่ฉันอยากทำคือโทร LogTable.DeleteItem (user_id) - โดยไม่ต้องระบุช่วงและให้มันลบทุกอย่างให้ฉัน

คำตอบ:


52

สิ่งที่ฉันอยากทำคือโทร LogTable.DeleteItem (user_id) - โดยไม่ต้องระบุช่วงและให้มันลบทุกอย่างให้ฉัน

คำขอที่เข้าใจได้แน่นอน ฉันสามารถจินตนาการได้ว่าการดำเนินการขั้นสูงเช่นนี้อาจถูกเพิ่มเข้ามาโดยทีม AWS เมื่อเวลาผ่านไป (พวกเขามีประวัติในการเริ่มต้นด้วยชุดคุณลักษณะที่ จำกัด ก่อนและประเมินส่วนขยายตามความคิดเห็นของลูกค้า) แต่นี่คือสิ่งที่คุณควรทำเพื่อหลีกเลี่ยงค่าใช้จ่าย การสแกนแบบเต็มอย่างน้อย:

  1. ใช้QueryแทนScanเพื่อดึงข้อมูลรายการทั้งหมดสำหรับuser_idซึ่งใช้งานได้โดยไม่คำนึงถึงคีย์หลักแฮช / ช่วงที่ใช้งานร่วมกันเนื่องจากHashKeyValueและRangeKeyConditionเป็นพารามิเตอร์แยกกันใน API นี้และเดิมกำหนดเป้าหมายเฉพาะค่าแอตทริบิวต์ของส่วนประกอบแฮชของคอมโพสิต คีย์หลัก .

    • โปรดทราบว่าคุณจะต้องจัดการกับเพจ API แบบสอบถามที่นี่ตามปกติดูพารามิเตอร์ExclusiveStartKey :

      คีย์หลักของรายการที่จะดำเนินการค้นหาก่อนหน้านี้ แบบสอบถามก่อนหน้านี้อาจให้ค่านี้เป็น LastEvaluatedKey หากการดำเนินการแบบสอบถามถูกขัดจังหวะก่อนที่จะดำเนินการแบบสอบถาม ไม่ว่าจะเป็นเพราะขนาดชุดผลลัพธ์หรือพารามิเตอร์ Limit LastEvaluatedKey สามารถส่งกลับในการร้องขอแบบสอบถามใหม่เพื่อดำเนินการต่อจากจุดนั้น

  2. วนซ้ำรายการที่ส่งคืนทั้งหมดและอำนวยความสะดวกDeleteItemตามปกติ

    • อัปเดต : BatchWriteItemส่วนใหญ่จะเหมาะสมกว่าสำหรับกรณีการใช้งานเช่นนี้ (ดูรายละเอียดด้านล่าง)

อัปเดต

ตามไฮไลต์โดยivantการดำเนินการBatchWriteItem ช่วยให้คุณสามารถใส่หรือลบหลายรายการในหลายตารางได้ในการเรียก API ครั้งเดียว [เน้นของฉัน] :

ในการอัปโหลดหนึ่งรายการคุณสามารถใช้ PutItem API และในการลบหนึ่งรายการคุณสามารถใช้ DeleteItem API อย่างไรก็ตามเมื่อคุณต้องการอัปโหลดหรือลบข้อมูลจำนวนมากเช่นอัปโหลดข้อมูลจำนวนมากจาก Amazon Elastic MapReduce (EMR) หรือย้ายข้อมูลจากฐานข้อมูลอื่นไปยัง Amazon DynamoDB API นี้เป็นทางเลือกที่มีประสิทธิภาพ

โปรดทราบว่าสิ่งนี้ยังคงมีข้อ จำกัด ที่เกี่ยวข้องโดยเฉพาะอย่างยิ่ง:

  • การดำเนินการสูงสุดในคำขอเดียว - คุณสามารถระบุการดำเนินการใส่หรือลบได้สูงสุด 25 รายการ อย่างไรก็ตามขนาดคำขอทั้งหมดต้องไม่เกิน 1 MB (เพย์โหลด HTTP)

  • ไม่ใช่การดำเนินการของอะตอม - การดำเนินการส่วนบุคคลที่ระบุใน BatchWriteItem เป็นอะตอม อย่างไรก็ตาม BatchWriteItem โดยรวมเป็นการดำเนินการ "สุดความพยายาม" ไม่ใช่การดำเนินการแบบปรมาณู นั่นคือในคำขอ BatchWriteItem การดำเนินการบางอย่างอาจสำเร็จและบางอย่างอาจล้มเหลว [... ]

อย่างไรก็ตามสิ่งนี้เห็นได้ชัดว่ามีผลประโยชน์อย่างมากสำหรับกรณีการใช้งานเช่นเดียวกับที่อยู่ในมือ


4
ฉันคิดว่ามันสมเหตุสมผลแล้วที่จะใช้การลบแบทช์สำหรับขั้นตอนที่สอง (มัน "มาสก์" เป็นการดำเนินการเขียนแบทช์ )
ivant

1
@ivant - ขอบคุณมากสำหรับคำใบ้ฟังก์ชันการลบ "masked" ของ BatchWriteItem นี้ทำให้ฉันหนีไปแล้ว ฉันได้อัปเดตคำตอบตามนั้น
Steffen Opel

สำหรับการลบด้วยBatchWriteItemรายการต้องระบุผ่านTableWriteItems
นีล

1
ลิงค์ไปยัง BatchWriteItem ตอนนี้docs.aws.amazon.com/amazondynamodb/latest/APIReference/…
Tony

4
ฉันตระหนักดีว่านี่เป็นเรื่องเก่าและ OP ไม่ได้กล่าวถึง SDK ภาษาใดภาษาหนึ่ง แต่ใน Python มีระดับสูงbatch_writer()ซึ่งเป็นส่วนหนึ่งของboto3.resource.TableAPI ที่จะ "จัดการบัฟเฟอร์และส่งรายการเป็นกลุ่มโดยอัตโนมัตินอกจากนี้ผู้เขียนแบตช์จะ ยังจัดการรายการที่ยังไม่ได้ประมวลผลโดยอัตโนมัติและส่งใหม่ตามต้องการ "นั่นคือกระดาษห่อหุ้มรอบ ๆ BatchWriteItem ที่จัดการส่วนที่น่ารำคาญ boto3.amazonaws.com/v1/documentation/api/latest/reference/…
ดาวอส

46

ตามเอกสาร DynamoDB คุณสามารถลบตารางทั้งหมดได้

ดูด้านล่าง:

"การลบทั้งตารางมีประสิทธิภาพมากกว่าการลบรายการทีละรายการอย่างมากซึ่งจะเพิ่มปริมาณงานเขียนเป็นสองเท่าเมื่อคุณดำเนินการลบมากเท่ากับการดำเนินการใส่"

หากคุณต้องการลบเฉพาะบางส่วนของข้อมูลของคุณคุณสามารถสร้างตารางแยกกันสำหรับแต่ละเดือนปีหรือที่ใกล้เคียงกัน ด้วยวิธีนี้คุณสามารถลบ "เดือนที่แล้ว" และเก็บข้อมูลส่วนที่เหลือของคุณไว้เหมือนเดิม

นี่คือวิธีที่คุณลบตารางใน Java โดยใช้ AWS SDK:

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

8
ฉันชอบคำตอบนี้เช่นกัน แต่ข้อควรระวัง: สิ่งนี้สามารถสร้างตารางจำนวนมากในระบบของคุณและเราจ่ายตามการจัดเตรียมตาราง ดังนั้นคุณต้องลดการจัดเตรียมหลังจากสิ้นเดือน (ถ้าตารางของคุณเป็นต่อเดือน) ในขณะที่ตารางนี้จะไม่ถูกลบ
Sergio MC Figueiredo

2
เห็นด้วยกับคำตอบนี้ใช้หากคุณต้องการลบระเบียนทั้งหมดจากตาราง แต่ที่นี่ผู้ถามต้องการลบรายการฐานผู้ใช้ไม่ใช่ทั้งตาราง
Ihtsham Minhas

1
การมีตารางตารางแยกกันสำหรับผู้ใช้แต่ละคนจะมีราคาแพงเนื่องจากราคา DynamoDB หนึ่งตารางต่อเดือนจะทำให้สิ่งต่างๆแย่ลง นี่เป็นคำตอบสำหรับปัญหาที่แตกต่างและเฉพาะเจาะจงมาก
André Werlang

11
การลบตารางอาจไม่ใช่ตัวเลือกที่น่าสนใจหากคุณใช้การจัดเตรียมอัตโนมัติเช่น CloudFormation เพื่อจัดการตารางของคุณเป็นส่วนหนึ่งของสแต็ก ฉันไม่ทราบวิธีง่ายๆในการทำให้ CloudFormation สร้างตารางที่คุณลบด้วยมือขึ้นมาใหม่
brabster

2
วิธีนี้ใช้เวลาค่อนข้างนานในการลบและสร้างตารางใหม่ (เมื่อจำเป็น) ทำให้ไม่สามารถใช้งานได้ตลอดเวลา คำถามระบุไว้อย่างชัดเจนว่าการลบข้อมูลผู้ใช้ซึ่งจะเป็นการแยกออกเป็นตารางแยกต่างหากสำหรับผู้ใช้แต่ละราย
André Werlang

13

หากคุณต้องการลบรายการหลังจากเวลาผ่านไปเช่นหลังจากหนึ่งเดือนให้ใช้ตัวเลือก Time To Live จะไม่นับหน่วยการเขียน

ในกรณีของคุณฉันจะเพิ่ม ttl เมื่อบันทึกหมดอายุและปล่อยทิ้งไว้หลังจากผู้ใช้ถูกลบ TTL จะตรวจสอบให้แน่ใจว่าบันทึกถูกลบออกในที่สุด

เมื่อเปิดใช้งาน Time To Live บนโต๊ะงานเบื้องหลังจะตรวจสอบแอตทริบิวต์ TTL ของรายการเพื่อดูว่าหมดอายุหรือไม่

โดยทั่วไป DynamoDB จะลบรายการที่หมดอายุภายใน 48 ชั่วโมงหลังจากหมดอายุ ระยะเวลาที่แน่นอนที่รายการจะถูกลบอย่างแท้จริงหลังจากหมดอายุนั้นขึ้นอยู่กับลักษณะของปริมาณงานและขนาดของตาราง รายการที่หมดอายุแล้วและยังไม่ถูกลบจะยังคงปรากฏในการอ่านการสืบค้นและการสแกน รายการเหล่านี้ยังคงสามารถอัปเดตได้และการอัปเดตที่สำเร็จในการเปลี่ยนแปลงหรือลบแอตทริบิวต์การหมดอายุจะได้รับเกียรติ

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


การเพิ่ม TTL เป็นการ "อัปเดต" (การดำเนินการเขียน) ฉันไม่แน่ใจว่าจะมีประโยชน์ใด ๆ จากการทำการ "อัปเดต" แทนการ "ลบ"
Tomer

คุณสามารถแทรกข้อมูลนั้นด้วยการเขียนต้นฉบับและอัปเดตด้วยการดำเนินการอัปเดตอื่น ๆ แน่นอนว่าไม่ใช่ตัวเลือกหากคุณมีข้อมูลจำนวนมากและต้องการลบทิ้ง แต่นี่เป็นตัวเลือกที่ถูกต้องสำหรับกรณีที่คุณสามารถมี ttl สำหรับข้อมูลที่คุณแทรกหรืออัปเดตได้
Lukas Liesis

1
ฉันเห็นด้วยหากมีการกำหนดค่า TTL ไว้แล้วและการล้างข้อมูลอาจรอได้ถึง 48 ชั่วโมงนั่นเป็นตัวเลือกที่ดีที่สุด ขออภัยหากฉันไม่ชัดเจน
Tomer

4

คำตอบของคำถามนี้ขึ้นอยู่กับจำนวนรายการขนาดและงบประมาณของคุณ ขึ้นอยู่กับว่าเรามี 3 กรณีดังต่อไปนี้:

1- จำนวนรายการและขนาดของรายการในตารางไม่มากนัก จากนั้น Steffen Opel กล่าวว่าคุณสามารถใช้ Query แทน Scan เพื่อดึงข้อมูลรายการทั้งหมดสำหรับ user_id จากนั้นวนซ้ำรายการที่ส่งคืนทั้งหมดและอำนวยความสะดวกDeleteItemหรือBatchWriteItem. แต่โปรดทราบว่าคุณอาจเผาผลาญความสามารถในการรับส่งข้อมูลได้มากที่นี่ ตัวอย่างเช่นพิจารณาสถานการณ์ที่คุณต้องลบ 1,000 รายการจากตาราง DynamoDB สมมติว่าแต่ละรายการมีขนาด 1 KB ทำให้มีข้อมูลประมาณ 1MB งานการลบจำนวนมากนี้จะต้องใช้หน่วยความจุการเขียนทั้งหมด 2,000 หน่วยสำหรับการสืบค้นและการลบ ในการโหลดข้อมูลนี้ภายใน 10 วินาที (ซึ่งถือว่าไม่เร็วในบางแอปพลิเคชัน) คุณจะต้องตั้งค่าปริมาณการเขียนที่จัดเตรียมไว้ของตารางเป็น 200 หน่วยความจุในการเขียน อย่างที่คุณเห็นมันสามารถใช้วิธีนี้ได้หากใช้กับสินค้าจำนวนน้อยหรือสินค้าขนาดเล็ก

2- เรามีสิ่งของจำนวนมากหรือสิ่งของที่มีขนาดใหญ่มากในโต๊ะและเราสามารถจัดเก็บได้ตามเวลาในตารางต่างๆ จากนั้นโจนาธานกล่าวว่าคุณสามารถลบตารางได้ ดีกว่ามาก แต่คิดว่าไม่เข้ากับกรณีของคุณ เนื่องจากคุณต้องการลบข้อมูลผู้ใช้ทั้งหมดไม่ว่าจะสร้างบันทึกเวลาใดก็ตามดังนั้นในกรณีนี้คุณจะไม่สามารถลบตารางใดตารางหนึ่งได้ หากคุณต้องการมีตารางแยกต่างหากสำหรับผู้ใช้แต่ละคนฉันเดาว่าจำนวนผู้ใช้สูงแสดงว่าราคาแพงมากและไม่สามารถใช้งานได้จริงสำหรับกรณีของคุณ

3- หากคุณมีข้อมูลจำนวนมากและคุณไม่สามารถแบ่งข้อมูลร้อนและเย็นออกเป็นตารางต่างๆได้และคุณต้องทำการลบขนาดใหญ่บ่อยๆ แต่น่าเสียดายที่ DynamoDB ไม่ใช่ตัวเลือกที่ดีสำหรับคุณเลย อาจแพงขึ้นหรือช้ามาก (ขึ้นอยู่กับงบประมาณของคุณ) ในกรณีเหล่านี้ขอแนะนำให้หาฐานข้อมูลอื่นสำหรับข้อมูลของคุณ


0

วิธีการของฉันในการลบแถวทั้งหมดออกจากตาราง i DynamoDb คือการดึงแถวทั้งหมดออกจากตารางโดยใช้ DynamoDbs ScanAsync จากนั้นฟีดรายการผลลัพธ์ไปยัง DynamoDbs AddDeleteItems ด้านล่างรหัสใน C # ใช้งานได้ดีสำหรับฉัน

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

หมายเหตุ: การลบตารางแล้วสร้างใหม่อีกครั้งจากเว็บคอนโซลอาจทำให้เกิดปัญหาหากใช้ YAML / CloudFront ในการสร้างตาราง


0

เราไม่มีตัวเลือกในการตัดทอนตารางไดนาโม เราต้องวางตารางแล้วสร้างใหม่ ค่าบริการ DynamoDB ขึ้นอยู่กับ ReadCapacityUnits & WriteCapacityUnits หากเราลบรายการทั้งหมดโดยใช้ฟังก์ชัน BatchWriteItem มันจะใช้ WriteCapacityUnits ดังนั้นควรลบระเบียนเฉพาะหรือลบตารางแล้วเริ่มใหม่อีกครั้ง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.