2010-10-06 2 views
114

Некоторые сотрудники и я вступили в дискуссию о наилучшем способе хранения исторических данных. В настоящее время для некоторых систем я использую отдельную таблицу для хранения исторических данных, и я сохраняю исходную таблицу для текущей активной записи. Итак, скажем, у меня есть таблица 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, но я хотел бы сохранить ответ общим и произвольным из любой СУБД.

ответ

50

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

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

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

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

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

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

+0

Думаю, я понимаю, что вы говорите. Итак, что я сделал с моей таблицей FOO_Hist, действительно создала таблицу аудита. Вместо того, чтобы использовать триггер для вставки в таблицу аудита при обновлении, я просто запустил инструкцию в программе. Это верно? – Aaron

+4

В значительной степени. Тем не менее, лучше вести такой журнал аудита с помощью триггеров; триггеры гарантируют, что любые изменения (включая исправления вручную) будут записаны в журналы аудита. Если у вас есть более 10-20 таблиц для аудита, вероятно, быстрее всего построить механизм запуска триггера. Если дисковый трафик для журналов аудита является проблемой, вы можете поместить таблицы журнала аудита на отдельный набор дисков. – ConcernedOfTunbridgeWells

+0

Да, я 100% согласен с этим. Спасибо. – Aaron

0

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

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

+0

Да, я могу разделить таблицы, но в том, что стандарт при работе с историческими данными? Следует ли включать исторические данные в ту же таблицу, что и активные данные? Это те вопросы, которые я хотел обсудить. Это также не является произвольным, поскольку оно относится к SQL Server 2008. – Aaron

24

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

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

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

Деталь/История Таблица, например, под названием Widget_Details, содержащего, по меньшей мере:

  • ID - первичный ключ. Деталь/исторический ID
  • MASTER_ID - например, в данном случае под названием «WIDGET_ID», это FK к основной записи
  • START_DATETIME - временной метки, указывающей начало этой базы данных строки
  • END_DATETIME - временной метки, указывающий конец эта строка базы данных
  • STATUS_CONTROL - одиночный столбец символов указывает статус строки. «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') версию записи.

+0

Привет Крис, если вы это сделаете, идентификатор (первичный ключ) должен быть изменен правильно? как насчет реляционной связи с другой таблицей, если она используется другими? – projo

+0

@projo ID на вашей главной таблице - это ПК и концептуально «ПК» для любой концепции, с которой вы имеете дело. Идентификатор в таблице подробностей - это ПК, чтобы идентифицировать историческую версию для мастера (это еще один столбец на деталях). При формировании отношений вы часто ссылаетесь на истинную PK вашей концепции (например, идентификатор вашей главной таблицы или столбец MASTER_ID на вашей детали) и используйте STATUS_CONTROL = 'C', чтобы убедиться, что вы получаете текущую версию. В качестве альтернативы вы можете ссылаться на идентификатор детали, чтобы связать что-то с определенным моментом времени. –

+0

+1 Я реализовал этот шаблон с большим успехом на нескольких крупных проектах. –

7

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

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

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

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

+1

Сложнее ли «JOIN» две таблицы в нескольких исторических отчетах или сложнее изменить каждую вставку/обновление/удаление таблицы, чтобы быть в курсе исторических проблем? Фактически, журнал аудита включал бы даже текущие данные в таблицу истории, поэтому текущая таблица даже не нужна в отчете. – 2013-06-13 14:29:31

-1

Другим вариантом является архивирование операционных данных на основе [ежедневно] почасово. Большинство двигателей баз данных support the extraction of the data into an archive.

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

  1. определяет текущие таблицы в оперативной базе данных
  2. выбирает все данные из каждой таблицы в файл CSV или XML
  3. сжимает экспортированные данные в файл 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 
+0

Не могли бы вы объяснить причину падения? – hamdiakoguz

+0

Это совсем не подходит для исторических данных, потому что, если кто-то изменяет значение и изменяет его обратно в цикле архива, эти обновления теряются. Также нет простого способа просмотреть изменения одного объекта с течением времени или частично восстановить объект. – Sgoettschkes

0

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

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

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

0

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

0

Просто хотел добавить параметр, который я начал использовать, потому что я использую 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 для записи до/после изменения. Затем я сохраняю эти значения в таблице истории с отметкой времени, когда произошло изменение (я также сохраняю идентификатор для текущей записи, вызывающей озабоченность). Используя процесс сериализации, я могу контролировать, как данные заполняются в случае изменений в схеме.

Я узнал об этом из этой ссылки here

Смежные вопросы