Який рекомендований спосіб видалити велику кількість елементів із DynamoDB?


111

Я пишу простий сервіс реєстрації в DynamoDB.

У мене є таблиця журналів, яка вводиться хешем user_id та діапазоном часових позначок (Unix epoch int).

Коли користувач послуги припиняє свій обліковий запис, мені потрібно видалити всі елементи таблиці, незалежно від значення діапазону.

Який рекомендований спосіб виконання подібних операцій (маючи на увазі, що можна видалити мільйони елементів)?

Наскільки я бачу, мої варіанти:

A: Виконайте операцію сканування, закликаючи видалити кожен повернутий елемент, поки не залишиться жодних елементів

B: Виконайте операцію BatchGet, знову закликаючи видалити кожен елемент, поки жодного не залишиться

І те й інше виглядає жахливо, оскільки це займе тривалий час.

Те, що я в ідеалі хочу зробити, це зателефонувати LogTable.DeleteItem (user_id) - Не надаючи діапазон, і потрібно видалити все для мене.

Відповіді:


52

Те, що я в ідеалі хочу зробити, це зателефонувати LogTable.DeleteItem (user_id) - Не надаючи діапазон, і потрібно видалити все для мене.

Зрозумілий запит справді; Я можу собі уявити, що така команда AWS може з часом додати просунуті операції, як-от такі, що вони можуть почати з обмеженого набору функцій і оцінити розширення на основі відгуків клієнтів), але ось що ви повинні зробити, щоб уникнути витрат на принаймні повне сканування:

  1. Використовуйте Запит, а не Сканувати для отримання всіх елементів для user_id- це працює незалежно від комбінованого первинного ключа хеш / діапазону, оскільки HashKeyValue і RangeKeyCondition - це окремі параметри цього API і колишній єдиний націлює значення атрибута хеш-компонента композиту первинний ключ. .

    • Зауважте, що вам доведеться мати справу із тимчасовим підключенням API запитів, як зазвичай, див. Параметр ExclusiveStartKey :

      Первинний ключ елемента, з якого слід продовжити попередній запит. Попередній запит може надати це значення як LastEvaluatedKey, якщо ця операція запиту була перервана перед завершенням запиту; або через розмір набору результатів або параметр Limit. LastEvaluatedKey може бути переданий у новому запиті запиту для продовження операції з цієї точки.

  2. Проведіть петлю над усіма поверненими елементами та полегшіть DeleteItem, як зазвичай

    • Оновлення : Швидше за все, BatchWriteItem більше підходить для подібного випадку використання (детальніше див. Нижче).

Оновлення

Як підкреслив ivant , операція BatchWriteItem дозволяє помістити або видалити декілька елементів у декількох таблицях в одному виклику API [мій акцент] :

Щоб завантажити один елемент, ви можете використовувати API PutItem, а для видалення одного елемента - API DeleteItem. Однак, коли ви хочете завантажити або видалити велику кількість даних, наприклад завантаження великих обсягів даних з Amazon Elastic MapReduce (EMR) або переміщення даних з іншої бази даних в Amazon DynamoDB, цей API пропонує ефективну альтернативу.

Зауважте, що це все ще має деякі відповідні обмеження, а саме:

  • Максимальна кількість операцій в одному запиті - Ви можете вказати до 25 операцій "поставити або видалити"; однак загальний розмір запиту не може перевищувати 1 Мб (корисна навантаження HTTP).

  • Не атомна операція - окремі операції, визначені в BatchWriteItem, є атомними; однак BatchWriteItem в цілому - це "найкращі зусилля", а не атомна. Тобто, у запиті BatchWriteItem деякі операції можуть бути успішними, а інші - невдалими. [...]

Тим не менш, це, очевидно, пропонує потенційно значну вигоду для випадків використання, таких як той, що знаходиться в наявності.


4
Я думаю, було б доцільно використовувати пакетне видалення для другого кроку (це "маскується" як операція запису пакетного пакету )
ivant

1
@ivant - велике спасибі за підказку, ця "маскована" функція видалення BatchWriteItem дійсно уникнула мене тоді; Відповідно я оновив відповідь.
Steffen Opel

для видалення з BatchWriteItemелементами потрібно вказати черезTableWriteItems
Ніл

1
Посилання на BatchWriteItem тепер docs.aws.amazon.com/amazondynamodb/latest/APIReference/…
Tony

3
Я усвідомлюю, що це старе, і ОП не згадував специфічну 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. Один стіл на місяць насправді погіршить ситуацію. Це однозначно відповідь на іншу, дуже специфічну проблему.
Андре Верланг

11
Видалення таблиці також не може бути привабливим варіантом, якщо ви використовуєте автоматизоване надання, наприклад, CloudFormation, для управління своєю таблицею як частиною стеку. Мені невідомий простий спосіб змусити CloudFormation відтворити таблицю, яку ви видалили вручну.
брабстер

2
Такий підхід вимагає досить багато часу, щоб видалити та відтворити (за потреби) таблицю, роблячи її недоступною протягом усього часу. У цьому питанні чітко сказано про видалення даних користувачів, що було б недоцільним розбиттям на окремі таблиці для кожного користувача.
Андре Верланг

13

Якщо ви хочете видалити елементи через деякий час, наприклад, через місяць, просто скористайтеся опцією Time To Live. Він не зараховуватиме одиниці запису.

У вашому випадку я б додав ttl, коли журнали закінчуються, і залишатиму їх після видалення користувача. TTL переконається, що журнали видаляться з часом.

Коли увімкнено час для живлення на столі, фонове завдання перевіряє атрибут 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 - це "оновлення" (операція запису). Я не впевнений, чи є користь для "оновлення" замість "видалення".
Томер

Ви можете вставити ці дані з оригінальним записом та оновити будь-якими іншими оновленнями. Звичайно, це не варіант, якщо у вас є маса даних, а потім ви хочете їх видалити. Але це дійсний варіант для випадків, коли ви можете мати ttl для даних, які ви вставляєте або оновлюєте.
Лукас Ліесіс

1
Я погоджуюся, якщо вже налаштовано TTL, і очищення може зачекати до 48 годин, це, безумовно, оптимальний варіант. Мої вибачення, якщо мені було незрозуміло.
Томер

4

Відповідь на це питання залежить від кількості позицій та їх розміру та вашого бюджету. Залежить від того, що у нас є 3 випадки:

1- Кількість предметів та розмір елементів у таблиці не дуже великі. то, як сказав Стеффен Опель, ви можете скористатися Запитом, а не Скануванням, щоб отримати всі елементи для user_id, а потім перевести цикл на всі повернені елементи та полегшити DeleteItemабоBatchWriteItem. Але майте на увазі, що тут ви можете спалити багато пропускної здатності. Наприклад, розглянемо ситуацію, коли потрібно видалити 1000 елементів із таблиці DynamoDB. Припустимо, що кожен елемент має розмір 1 КБ, що призводить до приблизно 1 МБ даних. Це завдання для групового видалення потребуватиме в цілому 2000 одиниць потужності запиту для запиту та видалення. Для виконання цього завантаження даних протягом 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.Так краще видалити конкретні записи або видалити таблицю і почати заново.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.