Таблица надгробий против удаленного флага в сценариях синхронизации и мягкого удаления базы данных

17

Мне нужно отслеживать удаленные элементы для синхронизации клиентов.

Как правило, лучше добавить таблицу-захоронение и триггер, который отслеживает удаление строки из базы данных сервера - в основном, добавляя новую строку в таблицу-захоронение с данными из удаленного элемента - или сохранять элементы в исходной таблицы и пометить их как удаленные, как правило, со столбцом типа bit, чтобы указать, что строка удалена, а другой столбец отслеживать, когда произошло удаление?

Лоренцо Полидори
источник

Ответы:

17

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

  • Как быстро должно быть удаление?
  • Как быстро должно быть удаление?
  • Как часто будут запрашиваться удаленные данные и будут ли они запрашиваться с данными, которые не были удалены?
  • Насколько быстрыми должны быть запросы удаленных данных?
  • Вам нужно сохранить только удаленные элементы или изменения?
  • Вам нужно, чтобы таблица / индексы первичной таблицы были небольшими?
  • Какие технологии разделения и / или отслеживания изменений доступны на платформе базы данных?
  • Сколько дискового пространства доступно?
  • Будет ли удаление происходить на лету или в пакетных операциях?
Ли Риффель
источник
Я вижу, это вопрос компромисса между различными системными требованиями. Если мне нужно быстрое удаление / удаление, этот флаг будет предпочтительнее, но если мне нужны быстрые запросы к удаленным элементам, а также к основной таблице, и, возможно, мне нужно отслеживать изменения любого типа, подход мог бы быть лучше.
Лоренцо Полидори
Ты понял. Могут даже быть случаи, когда предпочтительнее будет другой вариант. Например, если вам нужно, чтобы программные удаления были доступны только в течение 24 часов, в Oracle вы могли бы рассмотреть возможность установки гарантированного времени отмены и последующего использования ретроспективных запросов для просмотра удаленных данных.
Ли Риффель
5

Может быть, вы должны объединить два метода нарочно. Почему ???

Давайте использовать эту таблицу (MySQL-диалект)

CREATE TABLE mydata
(
    id int not null auto_increment
    firstname varchar(16) not null,
    lastname varchar(16) not null,
    zipcode char(5) not null,
    ...
    deleted tinyint not null default 0
    KEY (deleted,id),
    KEY (deleted,lastname,firstname,id),
    KEY (deleted,zipcode,id),
    KEY (lastname,firstname),
    KEY (zipcode),
    PRIMARY KEY (id)
);

Обратите внимание, что, за исключением PRIMARY KEY, каждому индексу, который вы создаете, должен предшествовать deletedфлаг и заканчиваться на id.

Давайте создадим надгробный стол

CREATE TABLE mytomb SELECT id FROM mydata WHERE 1=2;
ALTER TABLE mytomb ADD PRIMARY KEY (id);

Если у вашей таблицы уже есть deletedфлаг, вы можете заполнить таблицу с надписью

INSERT INTO mytomb SELECT id FROM mydata WHERE deleted = 1;

Хорошо, теперь данные и надгробная плита подготовлены. Как вы выполняете удаление?

Допустим, вы удаляете каждого человека из почтового индекса 07305. Вы бы запустили следующее:

INSERT IGNORE INTO mytomb SELECT id FROM mydata WHERE deleted=0 AND zipcode='07305';
UPDATE mydata SET deleted=1 WHERE deleted=0 AND zipcode='07305';

Хорошо, это выглядит как много накладных расходов в любом случае.

Теперь, вы хотите увидеть все удаленные данные? Вот два разных способа:

  • SELECT * FROM mydata WHERE deleted=1;
  • SELECT B.* FROM mytomb A INNER JOIN mydata B USING (id);

Если число идентификаторов в mytomb превышает 5% от количества строк в mydata, это полное сканирование таблицы. В противном случае выполняется сканирование индекса с поиском для каждой строки. Обратите внимание на любые ориентиры в этом отношении. Поиск объяснения планов.

Теперь, вы хотите увидеть каждого человека в почтовый индекс 07304? Вот два разных способа:

  • SELECT * FROM mydata WHERE deleted=1 AND zipcode='07304';
  • SELECT A.* FROM mydata A LEFT JOIN mytomb B USING (id) WHERE B.id IS NULL AND A.zipcode='07304'

Как насчет массовых удалений? Вот два разных способа:

  • DELETE FROM mydata WHERE deleted=1;
  • DELETE B.* FROM mytomb A INNER JOIN mydata B USING (id); DELETE FROM mytomb;

ВЫВОД

Теперь я не говорю, чтобы сохранить оба метода. Выполнение этого с течением времени показывает, какой метод является более быстрым с точки зрения общей работоспособности. Вы должны решить, какие тесты лучше всего подходят для запросов реальных данных, запросов к удаленным данным и массовых удалений.

RolandoMySQLDBA
источник
Есть ли преимущество в использовании обоих методов на постоянной основе? Или вы предлагаете просто использовать их параллельно для оценки производительности, а затем переходить к одному или другому?
Джон на все руки