Как управлять версиями записи в базе данных
предположим, что у меня есть запись в базе данных и что как администратор, так и обычные пользователи могут делать обновления.
может ли кто-нибудь предложить хороший подход/архитектуру, как управлять версиями каждого изменения в этой таблице, чтобы можно было откатить запись к предыдущей версии.
11 ответов:
Допустим, у вас есть
FOO
таблица, что администраторы и пользователи могут обновить. Большую часть времени вы можете писать запросы к таблице FOO. Счастливый день.тогда, я бы создал
FOO_HISTORY
таблица. Это имеет все столбцыFOO
таблица. Первичный ключ совпадает с Foo плюс столбец RevisionNumber. Есть внешний ключ отFOO_HISTORY
toFOO
. Вы также можете добавить столбцы, связанные с ревизией, такие как UserId и RevisionDate. Заполнения RevisionNumbers в постоянно растущей моде по всем*_HISTORY
таблицы (т. е. из последовательности Oracle или эквивалента). Не полагайтесь на то, что есть только одно изменение за секунду (т. е. не ставьтеRevisionDate
в первичный ключ).теперь, каждый раз, когда вы обновляете
FOO
, непосредственно перед обновлением вы вставляете старые значения вFOO_HISTORY
. Вы делаете это на каком-то фундаментальном уровне в своем дизайне, чтобы программисты не могли случайно пропустить этот шаг.если вы хотите удалить строку с
FOO
У вас есть несколько вариантов. Либо каскадируйте и удалите всю историю, либо выполните логическое удаление, отметивFOO
как удаленные.это решение хорошо, когда вы в значительной степени заинтересованы в текущих значениях и только иногда в истории. Если вам всегда нужна история, то вы можете поставить эффективные даты начала и окончания и сохранить все записи в
FOO
сам по себе. Затем каждый запрос должен проверить эти даты.
Я думаю, что вы ищете для управления версиями содержимого записей базы данных (как StackOverflow делает, когда кто-то редактирует вопрос/ответ). Хорошей отправной точкой может быть просмотр некоторой модели базы данных, которая использует редакция отслеживание.
лучший пример, который приходит на ум, это MediaWiki, движок Википедии. Сравните схему базы данных здесь, в частности таблица изменений.
в зависимости от того, какие технологии вы используя, Вы будете иметь, чтобы найти некоторые хорошие сравнения/слияния алгоритмов.
Регистрация этот вопрос если это для. NET.
в мире BI вы можете сделать это, добавив дату начала и дату окончания в таблицу, которую вы хотите изменить. При вставке первой записи в таблицу, startDate заполняется, но endDate имеет значение null. При вставке второй записи вы также обновляете дату окончания первой записи с датой начала второй записи.
Если вы хотите просмотреть текущую запись, вы выбираете тот, где endDate равен null.
это иногда называют типом 2 Медленно Меняется Размер. Смотрите также TupleVersioning
обновление до SQL 2008.
попробуйте использовать отслеживание изменений SQL в SQL 2008. Вместо временных меток и взломов столбцов tombstone вы можете использовать эту новую функцию для отслеживания изменений данных в вашей базе данных.
просто хотел добавить, что одним хорошим решением этой проблемы является использование временная база данных. Многие поставщики баз данных предлагают эту функцию либо из коробки, либо через расширение. Я успешно использовал временные таблицы расширение с PostgreSQL, но у других тоже есть. Всякий раз, когда вы обновляете запись в базе данных, база данных также сохраняет предыдущую версию этой записи.
два варианта:
- есть таблица истории-вставьте старые данные в эту таблицу истории всякий раз, когда оригинал обновляется.
- таблица аудита-храните значения до и после - только для измененных столбцов в таблице аудита вместе с другой информацией, например, кто обновил и когда.
вы не говорите, какая база данных, и я не вижу ее в тегах post. Если это для Oracle, я могу порекомендовать подход, который встроен в конструктор: use журнальные столы. Если это для любой другой базы данных, ну, я в основном рекомендую то же самое...
Как это работает, в случае, если вы хотите реплицировать его в другой БД, или, может быть, если вы просто хотите это понять, это то, что для таблицы есть теневая таблица, созданная тоже, просто обычная таблица базы данных, с те же спецификации полей, а также некоторые дополнительные поля: например, какое действие было предпринято в последний раз (строка, типичные значения "INS" для insert, "UPD" для update и "DEL" для delete), datetime для того, когда произошло действие, и идентификатор пользователя для того, кто это сделал.
через триггеры каждый действие в любую строку таблицы вставляет новую строку в таблицу журнала с новыми значениями, какое действие было выполнено, когда и каким пользователем. Вы никогда не удаляете строки (по крайней мере, не за последние несколько месяцев). Да он будет расти большой, легко миллионы строк, но вы можете легко отслеживать значение любой запись любой момент времени С начала ведения журнала или старые строки журнала были очищены в последний раз, и кто сделал последнее изменение.
в Oracle все, что вам нужно, генерируется автоматически как SQL-код, все, что вам нужно сделать, это скомпилировать/запустить его; и он поставляется с базовым приложением CRUD (на самом деле только "R"), чтобы проверить его.
вы можете выполнять аудит таблицы SQL с помощью триггеров SQL. Из триггера вы можете получить доступ к 2 специальным таблицам (inserted и deleted). Эти таблицы содержат точные строки, которые были вставлены или удалены при каждом обновлении таблицы. В триггер SQL, вы можете взять эти измененные строки и вставить их в таблицу аудита. Этот подход означает, что ваш аудит прозрачен для программиста; не требуя от них никаких усилий или каких-либо знаний о реализации.
дополнительный бонус этого подхода заключается в том, что аудит будет происходить независимо от того, была ли операция sql выполнена через ваши DLL доступа к данным или через ручной SQL-запрос; (поскольку аудит выполняется на самом сервере).
Я тоже делаю то же самое. Я делаю базу данных для планов уроков. Эти планы нуждаются в гибкости управления версиями атомарных изменений. Другими словами, каждое изменение, независимо от того, насколько оно мало, в планы уроков должно быть разрешено, но старая версия также должна быть сохранена. Таким образом, создатели уроков могут редактировать планы уроков, пока учащиеся их используют.
Как это будет работать, что как только студент сделал урок, их результаты прилагаются к версии они завершенный. Если изменение сделано, их результат всегда будет указывать на их версию.
таким образом, если критерии урока удалены или перемещены, их результаты не изменятся.
в настоящее время я делаю это, обрабатывая все данные в одной таблице. Обычно у меня было бы только одно поле id, но с этой системой я использую id и sub_id. Sub_id всегда остается со строкой, через обновления и удаления. Идентификатор автоматически увеличивается. План урока программное обеспечение ссылка на самый новый sub_id. Результаты студента будут связаны с идентификатором. Я также включил метку времени для отслеживания, когда произошли изменения, но не нужно обрабатывать управление версиями.
одна вещь, которую я мог бы изменить, как только я проверил ее, я мог бы использовать ранее упомянутую идею endDate null. В моей системе, чтобы найти самую новую версию, мне нужно будет найти max(id). Другая система просто ищет endDate = null. Не уверен, что преимущества outway имеют другую дату поле.
мои два цента.
While @WW. ответ-хороший ответ другой способ-сделать столбец версии и сохранить все ваши версии в одной таблице.
для одного подхода таблицы вы либо:
- используйте флаг, чтобы указать последнюю ala Word Press
- или сделать неприятный больше, чем версия
outer join
.пример SQL из
outer join
метод с использованием номера редакции это:SELECT tc.* FROM text_content tc LEFT OUTER JOIN text_content mc ON tc.path = mc.path AND mc.revision > tc.revision WHERE mc.revision is NULL AND tc.path = '/stuff' -- path in this case is our natural id.
плохая новость заключается в том, что выше требуется
outer join
и внешние соединения могут быть медленными. Хорошей новостью является то, что создание новых записей теоретически дешевле, потому что вы можете сделать это в одна операция записи без транзакций (предполагая, что ваша база данных является атомарным).пример создания новой редакции для
'/stuff'
может быть:INSERT INTO text_content (id, path, data, revision, revision_comment, enabled, create_time, update_time) ( SELECT (md5(random()::text)) -- {id} , tc.path , 'NEW' -- {data} , (tc.revision + 1) , 'UPDATE' -- {comment} , 't' -- {enabled} , tc.create_time , now() FROM text_content tc LEFT OUTER JOIN text_content mc ON tc.path = mc.path AND mc.revision > tc.revision WHERE mc.revision is NULL AND tc.path = '/stuff' -- {path} )
мы вставляем, используя старые данные. Это особенно полезно, если вы хотите обновить только один столбец и избегайте оптимистической блокировки и / или транзакций.
флаг подход и таблица истории подход требует два строки для вставки / обновления.
другое преимущество с
outer join
подход номер ревизии является то, что вы всегда можете выполнить рефакторинг с несколькими таблицами позже с триггеров, так как триггер должен по сути сделать что-то вроде выше.
Алок предложил
Audit table
выше, я хотел бы объяснить это в моем посте.Я принял этот дизайн без схемы, одной таблицы в своем проекте.
схема:
- id-целочисленное автоматическое приращение
- username-STRING
- tablename-STRING
- oldvalue-TEXT / JSON
- newvalue-TEXT / JSON
- createdon-DATETIME
эта таблица может содержать исторические записи для каждой таблицы все в одном месте, с полной историей объекта в одной записи. Эта таблица может заполняться с помощью триггеров / крючков, где изменяются данные, сохраняя старый и новый снимок значения целевой строки.
плюсы с этим дизайном:
- меньшее количество таблиц для управления историей.
- сохраняет полный снимок каждой строки старого и нового состояния.
- легкий для того чтобы искать на каждой таблице.
- может создать раздел по таблице.
- можно определить политику хранения данных в таблице.
минусы с этим дизайном:
- размер данных может быть большим, если система имеет частые изменения.