схема базы данных, подходящая для дельта-синхронизации - PullRequest
2 голосов
/ 13 января 2011

это вопрос только для обсуждения. Прямо сейчас мне нужно переделать таблицу базы данных mysql. По сути, эта таблица содержит все записи контракта, которые я синхронизировал из другой базы данных. Запись договора может быть изменена, удалена или пользователи могут добавлять новые записи договора через интерфейс GUI. На этом этапе структура таблицы в точности совпадает с информацией о контракте (столбец: серийный номер, срок действия и т. Д.). В этом случае я могу синхронизировать только всю таблицу (удалить все старые записи, заменить новыми). Если я хочу выполнить дельта (только синхронизацию с измененными, новыми, удаленными записями) синхронизацию таблицы, как мне изменить схему базы данных?

вот метод, который я придумаю, но мне нужны ваши предложения, потому что я думаю, что это распространенный сценарий в приложениях баз данных. 1) ввести концепцию / столбец порядкового номера: для каждой последовательности отметьте новые добавленные записи, измененные записи, удаленные записи с этим порядковым номером. Записав последний синхронизированный порядковый номер, передайте только те записи с более высоким порядковым номером;

2) поскольку удаленные контракты могут быть добавлены обратно, а исходная таблица имеет ограничения первичного ключа, следует ли мне создать другую таблицу для этих удаленных записей? или добавить столбец флага, чтобы указать, был ли удален этот контракт?

Надеюсь, я четко объясню свой вопрос. В любом случае, если вам известны какие-либо статьи или ваши собственные предложения по этому поводу, пожалуйста, дайте мне знать. Спасибо!

1 Ответ

8 голосов
/ 14 января 2011

Я думаю, что вы путаете с понятием дельты.

Либо вы получаете полную загрузку (весь набор данных), либо только изменения («дельта»).

Если вы имеете дело с полной загрузкой, вы можете сделать усечение + вставка. Таким образом, вам не придется иметь дело с новыми или старыми или удаляемыми строками. Это может оказаться невозможным из-за ограничений ссылочной целостности и т. Д.

Если вы получаете дельту, каждый ряд обычно делится на 1 из 2 категорий:

  1. Соответствующий ключ = UPDATE. Вы можете игнорировать строки с одинаковыми данными или перезаписать.
  2. Нет соответствующего ключа = INSERT

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

В случае дельты вы можете согласиться отправить строку с маркером удаления (флаг, дата). Затем вы можете решить, сохранять ли строку маркером удаления (автоматически обрабатывается (1) выше), или вам следует DELETE вашу строку. Я предлагаю сохранить его, потому что рано или поздно кто-то обвинит вас в пропущенных строках / плохом качестве данных, а затем вы бросите DELETE_DATE им в лицо.

Для MySQL вы можете использовать INSERT ... ON DUPLICATE KEY UPDATE для реализации функции "upsert".

Вы должны были бы предоставить более подробную информацию, если вам нужна более конкретная помощь.

Обновление:

Хорошо, вот пример. Скажем, у вас есть следующая структура таблицы:

create table contracts(
   contract_id int         not null
  ,details1    varchar(20)
  ,details2    varchar(20)
  ,delete_date date
  ,primary key(contract_id)
);

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

create table contracts_delta(
   contract_id int         not null
  ,details1    varchar(20)
  ,details2    varchar(20)
  ,delete_date date
  ,primary key(contract_id)
);

Некоторые примеры данных:

mysql> select * from contracts;
+-------------+----------+----------+-------------+
| contract_id | details1 | details2 | delete_date |
+-------------+----------+----------+-------------+
|           1 | a1       | a2       | NULL        |
|           2 | b1       | b2       | NULL        |
|           3 | c1       | c2       | 2011-01-03  |
+-------------+----------+----------+-------------+

mysql> select * from contracts_delta;
+-------------+----------+----------+-------------+
| contract_id | details1 | details2 | delete_date |
+-------------+----------+----------+-------------+
|           2 | b1       | b2       | 2011-01-03  | <-- Row was deleted
|           3 | c1       | c2       | NULL        | <-- No longer deleted
|           4 | d1       | d2       | NULL        | <-- This is new row
+-------------+----------+----------+-------------+

Используя синтаксис, на который я ссылался ранее, вы можете вставить все новые строки. Всякий раз, когда строка уже есть (на дубликате), мы вместо этого решили обновить столбцы. Обратите внимание, что это обрабатывает удаленные строки автоматически, так как delete_date является обычным столбцом, как и все остальное.

insert 
  into contracts(
        contract_id
       ,details1
       ,details2
       ,delete_date
       )
 select contract_id
       ,details1
       ,details2
       ,delete_date
  from contracts_delta s
    on duplicate key 
    update contracts.details1    = s.details1
          ,contracts.details2    = s.details2
          ,contracts.delete_date = s.delete_date;

После "upsert" данные в контрактах будут выглядеть так:

mysql> select * from contracts;
+-------------+----------+----------+-------------+
| contract_id | details1 | details2 | delete_date |
+-------------+----------+----------+-------------+
|           1 | a1       | a2       | NULL        |
|           2 | b1       | b2       | 2011-01-03  |
|           3 | c1       | c2       | NULL        |
|           4 | d1       | d2       | NULL        |
+-------------+----------+----------+-------------+

- В этот момент вы можете удалить дельта-таблицу (не забудьте создать ее заново в следующий раз)

drop table contracts_delta;

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

truncate table contracts_delta;

- Или вы можете сохранить фактическую дельту (переименовать таблицу), если вам когда-нибудь понадобятся отдельные дельты

alter table contracts_delta rename to contracts_delta_20110115;
...