Как хранить исторические данные

Некоторые сотрудники, и я вошел в дебаты о наилучшем способе хранения исторических данных. В настоящее время для некоторых систем я использую отдельную таблицу для хранения исторических данных, и я сохраняю исходную таблицу для текущей активной записи. Итак, скажем, у меня есть таблица FOO. В моей системе все активные записи будут поступать в FOO, и все исторические записи будут опубликованы в FOO_Hist. Пользователь может обновить много разных полей в FOO, поэтому я хочу сохранить точную учетную запись обо всем обновленном. FOO_Hist содержит те же поля, что и FOO, за исключением автоматического инкремента HIST_ID. Каждый раз, когда FOO обновляется, я выполняю инструкцию insert в FOO_Hist, подобную: insert into FOO_HIST select * from FOO where id = @id.

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

Существует ли стандарт для хранения исторических данных? Мне кажется, что я не хочу загромождать свои активные записи со всеми моими историческими записями в одной таблице, учитывая, что может быть более миллиона записей (я думаю, что надолго).

Как вы или ваша компания справляетесь с этим?

Я использую MS SQL Server 2008, но я хотел бы сохранить ответ общим и произвольным из любой СУБД.

Ответ 1

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

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

  • Ведение журнала аудита: Это лучше сделать с таблицами аудита. Достаточно легко написать инструмент, который генерирует скрипты для создания таблиц журналов аудита и триггеров путем чтения метаданных из словаря системных данных. Этот тип инструмента можно использовать для модернизации журнала аудита в большинстве систем. Вы также можете использовать эту подсистему для изменения захвата данных, если вы хотите реализовать хранилище данных (см. Ниже).

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

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

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

Ответ 2

Я не думаю, что есть определенный стандартный способ сделать это, но я думал, что буду использовать возможный метод. Я работаю в Oracle и нашей собственной инфраструктуре веб-приложений, которая использует XML для хранения данных приложений.

Мы используем что-то, называемое моделью Master-Detail, которая в ней проще всего состоит из:

Основная таблица, например, называется Widgets, которая часто содержит идентификатор. Часто будут содержать данные, которые не будут меняться со временем/не являются историческими.

Таблица деталей/истории, например, называется Widget_Details, содержащая по крайней мере:

  • ID - первичный ключ. Детальный/исторический идентификатор
  • MASTER_ID - например, в этом случае называется WIDGET_ID, это FK для основной записи
  • START_DATETIME - отметка времени, указывающая начало этой строки базы данных
  • END_DATETIME - отметка времени, указывающая конец этой строки базы данных
  • STATUS_CONTROL - одиночный столбец char указывает статус строки. "C" указывает, что текущий, NULL или "A" будет историческим/архивированным. Мы используем это только потому, что мы не можем индексировать по END_DATETIME значение NULL
  • CREATED_BY_WUA_ID - сохраняет идентификатор учетной записи, которая вызвала создание строки.
  • XMLDATA - сохраняет фактические данные

Таким образом, сущность начинается с того, что 1 строка в главной и 1 строке подробно описана. Деталь имеет дату окончания NULL и STATUS_CONTROL для 'C'. Когда происходит обновление, текущая строка обновляется до END_DATETIME текущего времени, а для параметра status_control установлено значение NULL (или "A", если это необходимо). В таблице подробностей создается новая строка, все еще связанная с одним и тем же мастером, с статусом status_control 'C', идентификатором человека, делающего обновление, и новыми данными, хранящимися в столбце XMLDATA.

Это основа нашей исторической модели. Логика Create/Update обрабатывается в пакете Oracle PL/SQL, поэтому вы просто передаете функцию текущему идентификатору, вашему идентификатору пользователя и новым XML-данным, и внутренне он выполняет все обновление/вставку строк, чтобы представить это в исторической модели, Время начала и окончания указывает, когда активна эта строка в таблице.

Хранение дешево, мы обычно не удаляем данные и предпочитаем сохранять контрольный журнал. Это позволяет нам видеть, как выглядели наши данные в любой момент времени. Индексируя status_control = 'C' или используя View, загромождение не является проблемой. Очевидно, что ваши запросы должны учитываться, вы всегда должны использовать текущую (NULL end_datetime и status_control = 'C') версию записи.

Ответ 3

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

Если вы попробуете другой подход достаточно скоро, вы столкнетесь с проблемами:

  • расходы на обслуживание
  • больше флажков при выборе
  • замедления запросов
  • рост таблиц, индексов

Ответ 4

этот вопрос довольно старый, но люди все еще работают над этой проблемой. поэтому, если вы используете oracle, вам может быть интересен ретроспективный кадр оракула: http://docs.oracle.com/cd/B28359_01/appdev.111/b28424/adfns_flashback.htm

Ответ 6

В SQL Server 2016 и более поздних версиях появилась новая функция, которая называется Temporal Tables и предназначена для решения этой проблемы с минимальными усилиями разработчика. Концепция временной таблицы похожа на сбор данных изменений (CDC), с той разницей, что временная таблица абстрагирует большинство вещей, которые вам приходилось делать вручную, если вы использовали CDC.

Ответ 7

Вы можете просто разбивать таблицы no?

"Стратегии разделенных таблиц и индексов с использованием SQL Server 2008 Когда таблица базы данных возрастает с размерами до сотен гигабайт или более, становится сложнее загружать новые данные, удалять старые данные и поддерживать индексы. Просто большой размер таблицы заставляет такие операции занимать гораздо больше времени. Даже данные, которые должны быть загружены или удалены, могут быть очень важными, делая операции INSERT и DELETE на столе нецелесообразными. Программное обеспечение базы данных Microsoft SQL Server 2008 обеспечивает разбиение на таблицы, чтобы сделать такие операции более управляемыми ".

Ответ 8

Реальный вопрос: вам нужно использовать исторические данные и активные данные для отчетности? Если так держать их в одной таблице, разделяйте и создавайте представление для активных записей для использования в активных запросах. Если вам нужно только время от времени смотреть на них (исследовать проблемы с лигалом или некоторые из них), поместите их в отдельную таблицу.

Ответ 9

Другим вариантом является архивирование операционных данных на основе [ежедневный/часовой]. Большинство двигателей баз данных поддерживают извлечение данных в архив.

В принципе, идея состоит в том, чтобы создать запланированное задание Windows или CRON, которое

  • определяет текущие таблицы в рабочей базе данных
  • выбирает все данные из каждой таблицы в файл CSV или XML
  • сжимает экспортированные данные в файл ZIP, желательно с меткой времени генерации в имени файла для упрощения архивирования.

Многие двигатели баз данных SQL имеют инструмент, который можно использовать для этой цели. Например, при использовании MySQL в Linux следующая команда может использоваться в задании CRON для планирования извлечения:

mysqldump --all-databases --xml --lock-tables=false -ppassword | gzip -c | cat > /media/bak/servername-$(date +%Y-%m-%d)-mysql.xml.gz

Ответ 10

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

Аудит (цель безопасности). Используйте общую таблицу для всех ваших аудируемых таблиц. определить структуру для хранения имени столбца, перед значением и после полей значений.

Архив/Исторический: для случаев, таких как отслеживание предыдущего адреса, номера телефона и т.д., создание отдельной таблицы FOO_HIST лучше, если ваша схема активной таблицы транзакций не изменится значительно в будущем (если ваша история таблица должна иметь одинаковую структуру). если вы ожидаете нормализации таблицы, тип данных измените добавление/удаление столбцов, сохраните свои исторические данные в формате xml. определить таблицу со следующими столбцами (ID, Date, Version Schema Version, XMLData). это легко справится с изменениями схемы. но вам нужно иметь дело с xml, и это может привести к усложнению для извлечения данных.

Ответ 12

Вы можете создать материализованные/индексированные представления в таблице. Исходя из вашего требования, вы можете выполнить полное или частичное обновление представлений. См. Это, чтобы создать mview и журнал. Как создать материализованные представления в SQL Server?

Ответ 13

Просто хотел добавить параметр, который я начал использовать, потому что я использую Azure SQL, и для меня это было слишком громоздким. Я добавил триггер insert/update/delete в свою таблицу, а затем преобразовал до/после изменения в json, используя функцию "FOR JSON AUTO".

 SET @beforeJson = (SELECT * FROM DELETED FOR JSON AUTO)
SET @afterJson = (SELECT * FROM INSERTED FOR JSON AUTO)

Это возвращает представление JSON для записи до/после изменения. Затем я сохраняю эти значения в таблице истории с отметкой времени, когда произошло изменение (я также сохраняю идентификатор для текущей записи, вызывающей озабоченность). Используя процесс сериализации, я могу контролировать, как данные заполняются в случае изменений в схеме.

Я узнал об этом по этой ссылке здесь