Эффективное хранение наборов пар ключ-значение с совершенно разными ключами

9

Я унаследовал приложение, которое связывает множество различных видов деятельности с сайтом. Существует около 100 различных видов деятельности, и каждый из них имеет различный набор из 3-10 полей. Однако все действия имеют как минимум одно поле даты (может быть любое сочетание даты, даты начала, даты окончания, запланированной даты начала и т. Д.) И одно поле ответственного лица. Все остальные поля сильно различаются, и поле даты начала не обязательно будет называться «Дата начала».

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

введите описание изображения здесь

Каждое действие имеет несколько полей деятельности; каждый сайт имеет несколько действий, и таблица SiteActivityData хранит KVP для каждого объекта SiteActivity.

Это делает (веб-приложение) приложение очень простым для кодирования, потому что все, что вам действительно нужно сделать, - это перебрать записи в SiteActivityData для данного действия и добавить метку и элемент управления вводом для каждой строки в форму. Но есть много проблем:

  • Целостность это плохо; в SiteActivityData можно поместить поле, которое не относится к типу действия, а DataValue является полем varchar, поэтому необходимо постоянно приводить числа и даты.
  • Отчетность и специальные запросы этих данных сложны, подвержены ошибкам и медленны. Например, для получения списка всех действий определенного типа с конечной датой в указанном диапазоне требуются сводки и приведения типов к датам. Авторы отчетов ненавидят эту схему, и я их не виню.

Поэтому я ищу способ хранения большого количества действий, которые почти не имеют общих полей, чтобы упростить отчетность. До сих пор я придумал, как использовать XML для хранения данных активности в формате псевдо-noSQL:

введите описание изображения здесь

Таблица Activity будет содержать XSD для каждого действия, что устраняет необходимость в таблице ActivityField. SiteActivity будет содержать ключ-значение XML, поэтому каждое действие для сайта теперь будет находиться в одной строке.

Деятельность выглядела бы примерно так (но я еще не полностью ее описал):

<SomeActivityType>
  <SomeDateField type="StartDate">2000-01-01</SomeDateField>
  <AnotherDateField type="EndDate">2011-01-01</AnotherDateField>
  <EmployeeId type="ResponsiblePerson">1234</EmployeeId>
  <SomeTextField>blah blah</SomeTextField>
  ...

Преимущества:

  • XSD будет проверять XML, отлавливая ошибки, такие как помещение строки в числовое поле на уровне базы данных, что было невозможно при старой схеме, в которой все хранилось в varchar.
  • Набор записей KVP, который используется для создания веб-форм, может быть легко воспроизведен с использованием select ... from ActivityXML.nodes('/SomeActivityType/*') as T(r)
  • Подзапрос xpath XML можно использовать для создания результирующего набора, в котором есть столбцы для даты начала, даты окончания и т. Д., Без использования сводной точки, что-то вроде select ActivityXML.value('.[@type=StartDate]', 'datetime') as StartDate, ActivityXML.value('.[@type=EndDate]', 'datetime') as EndDate from SiteActivity where...

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

Дополнительный вопрос: если я определю тег как имеющий тип данных даты в XSD с использованием xs:date, собирается ли SQL Server индексировать его как значение даты? Я обеспокоен тем, что, если я сделаю запрос по дате, он должен будет привести строку даты к значению даты и исключить любую возможность использования индекса.

Пол Эбботт
источник
Насколько актуальными должны быть данные для отчетов? Будут ли отчеты попадать в производство?
Джеймс Андерсон
Большинство отчетов в настоящее время попадают в хранилище данных (которое на самом деле не является DW, по сути это копия производственной транзакционной схемы с добавлением множества видов и таблиц из других баз данных). Наличие отчетов, которые являются устаревшим днем, приемлемо, но это было бы бонусом, если бы оно могло быть живым.
Пол Эбботт
Сколько перекрытий в полях? Десять полей охватывают все 100 подтипов, или есть ~ 500 совершенно разных полей?
Джон на все руки
Есть 72 поля и 75 видов деятельности. 30 полей используются только одним действием, а большинство остальных используется 5-10 действиями. Есть несколько полей, которые используются ~ 30 различными видами деятельности. По большей части, между действиями не так много общего.
Пол Эбботт

Ответы:

7

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

Недостаточно репутации, чтобы прокомментировать сначала, так что поехали!

Если основной целью является создание отчетов, и у вас есть DW (даже если это не звездообразная схема), я бы рекомендовал попытаться включить это в звездообразную схему. Преимущества - быстрые, простые запросы. Недостатком является ETL, но вы уже подумываете о переносе данных в новый дизайн, и ETL в звездообразную схему, вероятно, проще построить и поддерживать, чем решение для оболочки XML (а SSIS включен в лицензию SQL Server). Кроме того, он запускает процесс признанного дизайна отчетности / аналитики.

Так как это сделать ... Похоже, у вас есть то, что известно как Бессмысленный Факт . Это пересечение атрибутов, которые определяют событие без связанной меры (например, продажная цена). У вас есть даты для некоторых или всех ваших мероприятий? Вероятно, у вас должно быть пересечение Активности, Сайта и Даты.

DimActivity- Я предполагаю, что есть шаблон, который может позволить вам разбить их на хотя бы относительно общие столбцы. Если так, у вас может быть три? пять? размеры для занятий. В худшем случае у вас есть пара непротиворечивых столбцов, таких как имя деятельности, вы можете фильтровать их, и вы оставляете общие заголовки, такие как «Атрибут1» и т. Д. Для оставшихся случайных деталей.

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

DimSite- кажется прямым, поэтому мы опишем суррогатные ключи здесь. По сути, это просто увеличивающийся уникальный идентификатор. Столбец Integer Identity является общим. Это позволяет разделить DW и исходные системы и обеспечивает оптимальные объединения в хранилище данных. Ваш естественный ключ или бизнес-ключ обычно сохраняется, но для технического обслуживания / проектирования не анализируется и не присоединяется. Пример схемы:

CREATE TABLE [DIM].[Site]
(
 SiteSK INT NOT NULL IDENTITY PRIMARY KEY
,SiteNK INT NOT NULL --source system key
,SiteName VARCHAR(500) NOT NULL
)

DimDate- атрибуты даты. Сделайте «умный ключ» вместо удостоверения личности. Это означает, что вы можете ввести значащее целое число, которое относится к дате для запросов, например WHERE DateSK = 20150708. Существует множество бесплатных сценариев для загрузки DimDate, и в большинстве из них включен этот смарт-ключ. ( один вариант )

DimEmployee - ваш XML включил это, если это более общее изменение в DimPerson, и заполните соответствующими атрибутами лица, поскольку они доступны и имеют отношение к отчетности.

И ваш факт:

FactActivitySite
DimSiteSK - FK to DimSite
DimActivitySK - FK to DimActivity
DimEmployee - FK to DimEmployee
DimDateSK - FK to DimDate

Вы можете переименовать их в факте, и вы можете иметь несколько ключей даты на событие. Факты, как правило, очень велики, поэтому избегать обновлений, как правило, хорошо ... если у вас есть несколько обновлений дат для одного события, вы можете попробовать удалить / вставить дизайн, добавив SK к факту, который позволяет выбирать строки «обновления» для удалить, а затем вставить последние данные.

Расширьте факт дату , чтобы все , что вам нужно: StartDateSK, EndDateSK, ScheduledStartDateSK.

Все измерения должны иметь неизвестную строку, обычно с жестким кодом -1 SK. Когда вы загружаете факт, и у активности нет ни одной из включенных дат, она должна просто загрузить -1.

Фактом является набор целочисленных ссылок на ваши атрибуты, хранящиеся в измерениях, соединяйте их вместе, и вы получаете все свои данные в очень чистом шаблоне соединения, а факт, благодаря его типам данных, исключительно мал и быстр. Поскольку вы находитесь в SQL Server, добавьте индекс columnstore для дальнейшего повышения производительности. Вы можете просто уронить его и восстановить во время ETL. Как только вы попадаете в SQL 2014+, вы можете писать в индексы columnstore.

введите описание изображения здесь

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

Дейв
источник
(вопрос от wesdev): @Dave, какой инструмент ERD вы использовали?
ypercubeᵀᴹ
Это было сделано в Microsoft Visio 2013
Дейв