Право на забвение в базе данных — Примеры

Пример 1 — Один идентификатор, который достаёт до всего

Пришёл запрос на удаление, и команда вручную ищет клиента: идентификатор пользователя есть в одних хранилищах, адрес почты — в других. Схема ниже копирует почту человека в каждую таблицу, которой касается. Разберитесь, что делает следующий запрос дешёвым, и напишите поля, которые несут связь вместо копии.

users.id
orders.customer_email      скопирован, а не связан
events.email

Решение

users.id                  идентификатор субъекта, выданный один раз
orders.user_id            ссылайтесь на users.id; email не копируйте
events.subject_id         тот же идентификатор, распространённый на аналитику
logs.subject_id           структурное логирование несёт его рядом с IP

Распространение одного устойчивого идентификатора на каждое хранилище — базу, логи, аналитику, очередь, поисковый индекс и хранилище данных — превращает следующий запрос в запрос к базе, а не в неделю поиска связей. Скопированный адрес почты — вторая вещь, которую надо найти и удалить, и забывают обычно именно копию. Обычная ошибка — проектировать это после прихода запроса; всё, что нужно, — один идентификатор, а внедрение задним числом дороже ровно в ту же работу.

Пример 2 — Удалить, обезличить или сохранить

Пишется процедура удаления, и первый черновик удаляет каждую строку, где упомянут человек, включая заказы, нужные бухгалтерии. Решите по каждому полю для одного человека и сохраните процедуру, чтобы второй запрос был выполнением, а не проектом.

черновик процедуры
  delete from users where id = ?
  delete from orders where user_id = ?

Решение

begin;
  delete from users where id = :subject;          -- профиль, email, телефон
  update orders
     set customer_ref = 'erased-' || :hash        -- обезличить ссылку
   where user_id = :subject;
  -- сохранить: сумму заказа, дату, позиции (нормативное хранение)
  insert into erasure_log (subject, run_at, action) values (:subject, now(), 'erased');
commit;

Удаление не означает удалить заказ: транзакция нужна бухгалтерии, а персональные поля внутри неё — нет, поэтому ссылка заменяется надгробием, а агрегат остаётся. Если написать процедуру и её журнал скриптом, следующий запрос даст доказательство того, что было удалено или сохранено. Обычная ошибка — забыть неизменяемые копии: резервные копии, журналы только для добавления и потоки событий возвращают данные после восстановления, если не применять список надгробий при восстановлении.