База данных - Версии данных
Я прочитал несколько вопросов о SO (например, этот) в отношении версий ваших данных в базе данных.
Мне понравились некоторые из упомянутых предложений. Я долгое время хотел (необходимости) пересмотреть многие мои таблицы, но так и не добрался до него. Будучи программистом с простой работой с базой данных под моим поясом, мне было интересно, как это вообще можно было бы сделать.
Я не запрашиваю фактическое решение в синтаксисе SQL. В конце концов я смогу понять это для себя (или опубликую СО, когда придет время). Я просто прошу людей прокомментировать, как они это сделают, и любые потенциальные проблемы с производительностью, которые могут возникнуть, если я буду "пересматривать" сотни миллионов записей. Или любые другие предложения, если они основаны на приведенном ниже примере.
Учитывая простой пример:
Person
------------------------------------------------
ID UINT NOT NULL,
PersonID UINT NOT NULL,
Name VARCHAR(200) NOT NULL,
DOB DATE NOT NULL,
Email VARCHAR(100) NOT NULL
Audit
------------------------------------------------
ID UINT NOT NULL,
UserID UINT NOT NULL, -- Who
TableName VARCHAR(50) NOT NULL, -- What
OldRecID UINT NOT NULL, -- Where
NewRecID UINT NOT NULL,
AffectedOn DATE NOT NULL, -- When
Comment VARCHAR(500) NOT NULL -- Why
Я не уверен, как связать таблицу Audit с любыми другими таблицами (например, Person), если TableName является строкой?
Кроме того, предполагая, что у меня есть три GUI для заполнения:
- Полная запись для идентификатора конкретного человека
- В виде таблицы перечислены все лица (по id)
- Вид, показывающий каждого человека с информацией о его пересмотре ниже каждой записи (# ревизий на человека, даты пересмотров, комментарии к пересмотру и т.д.), упорядоченные по последним версиям.
Чтобы выполнить 1 и 2, было бы лучше запросить таблицу Person или таблицу аудита?
Чтобы выполнить 3, может ли так называемый эксперт базы данных просто получить все записи и передать их на программное обеспечение для обработки или группу по идентификатору PersonID и Affected date? Обычно ли это обрабатывается одним запросом или многими?
Ответы
Ответ 1
Я выполнял различные схемы аудита на протяжении многих лет, и сейчас я собираюсь реализовать что-то вроде этого:
Person
------------------------------------------------
ID UINT NOT NULL,
PersonID UINT NOT NULL,
Name VARCHAR(200) NOT NULL,
DOB DATE NOT NULL,
Email VARCHAR(100) NOT NULL
Person_History
------------------------------------------------
ID UINT NOT NULL,
PersonID UINT NOT NULL,
Name VARCHAR(200) NOT NULL,
DOB DATE NOT NULL,
Email VARCHAR(100) NOT NULL
AuditID UINT NOT NULL
Audit
------------------------------------------------
ID UINT NOT NULL,
UserID UINT NOT NULL, -- Who
AffectedOn DATE NOT NULL, -- When
Comment VARCHAR(500) NOT NULL -- Why
Текущие записи всегда находятся в таблице Person. Если есть изменение, создается запись аудита и старая запись копируется в таблицу Person_History (обратите внимание, что идентификатор не изменяется и может быть несколько версий).
Идентификатор аудита находится в таблицах * _History, поэтому вы можете связать несколько записей с одной записью аудита, если хотите.
EDIT:
Если у вас нет отдельной таблицы истории для каждой базовой таблицы и вы хотите использовать ту же таблицу для хранения старых и "удаленных" записей, вы должны пометить записи флагом состояния. Проблема с тем, что это настоящая боль при запросе текущих записей - поверьте мне, я это сделал.
Ответ 2
Как насчет того, чтобы вы создали таблицу в обычном режиме, на каждой записи (и ModifiedBy, если хотите), есть столбец ModifiedDate, а также весь доступ к данным через материализованное представление, которое группирует данные по идентификатору, а затем делает HAVING ModifiedDate = MAX (ModifiedDate)?
Таким образом, добавление новой записи с тем же идентификатором, что и другой, приведет к удалению старой записи из представления. Если вы хотите запросить историю, не просматривайте представление
Я всегда обнаружил, что различные таблицы с одинаковыми столбцами являются сложными и подверженными ошибкам.
Ответ 3
Следуя сообщению DJ в истории таблицы для каждой базовой таблицы и комментариях Карла о возможных проблемах с производительностью, я немного поработал над SQL-исследованием, чтобы выяснить самый быстрый способ переноса записи из одной таблицы в другой.
Я просто хотел документировать, что я нашел:
Я подумал, что мне нужно будет выполнить выборку SQL для загрузки записи из базовой таблицы, а затем с помощью SQL push, чтобы поместить запись в таблицу истории, а затем обновить базовую таблицу, чтобы вставить измененные данные, Всего 3 транзакции.
Но, к моему удивлению, я понял, что вы можете сделать первые две транзакции, используя один оператор SQL, используя синтаксис SELECT INTO. Я уверен, что производительность будет в сто раз быстрее делать это.
Тогда это оставит нас просто ОБНОВИТЬ запись с новыми данными в базовой таблице.
Я все еще не нашел один оператор SQL для выполнения всех трех транзакций одновременно (я сомневаюсь, что это произойдет).
Ответ 4
Мне нравится ваша аудиторская таблица, ее хороший старт. У вас есть проблема с кардинальностью в вашей таблице аудита, поэтому я бы разоблачил ее как две таблицы:
Person
------------------------------------------------
ID UINT NOT NULL,
PersonID UINT NOT NULL,
Name VARCHAR(200) NOT NULL,
DOB DATE NOT NULL,
Email VARCHAR(100) NOT NULL,
AuditID UINT NOT NULL
Audit
------------------------------------------------
ID UINT NOT NULL,
TableName VARCHAR(50) NOT NULL, -- What
TableKey UINT NOT NULL,
CreateDate DATETIME NOT NULL DEFAULT(NOW),
CreateUserID UINT NOT NULL,
ChangeDate DATETIME NOT NULL DEFAULT(NOW),
ChangeUserID UINT NOT NULL
Audit_Item
------------------------------------------------
ID UINT NOT NULL,
AuditID UINT NOT NULL, -- Which audit record
UserID UINT NOT NULL, -- Who
OldRecID UINT NOT NULL, -- Where
NewRecID UINT NOT NULL,
AffectedOn DATE NOT NULL, -- When
Comment VARCHAR(500) NOT NULL -- Why
В предложенном исходном макете имеется одна запись аудита, которая указывает на (я предполагаю) две записи Person. Задачами этого проекта являются:
- Какие записи в вашей таблице
текущие "реальные" записи?
- Как вы представляете всю историю
изменений в записи Person? Если
вы указываете на две записи в
таблицу Person, затем см. пункт № 1:
какой из них является текущей записью?
- Сбрасываются поля Create *, Change *
из коллекции Audit_Item
записей. Они существуют только для
Простота доступа.
- Ключ AuditID в таблице Person позволяет вам указывать
вернуться к таблице аудита и перейти к
история отдельного Лица
без необходимости запрашивать аудит
таблица с предложением
WHERE
TableName='Person'