Является ли плохой практикой объединять данные из разных таблиц в одну?

12

Фон

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

Проблема

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

Мое "решение"

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

Таблица будет тонкой и длинной, хранящей только необходимые данные, что-то вроде этого:

CREATE TABLE dbo.HCM_Event_Log (
    id INT IDENTITY,
    type_id INT NULL,
    orig_id VARCHAR(36) NULL,
    patient_id UNIQUEIDENTIFIER NOT NULL,
    visit_id UNIQUEIDENTIFIER NULL,
    lookup_id VARCHAR(50) NULL,
    status VARCHAR(15) NULL,
    ordered_datetime DATETIME NULL,
    completed_datetime DATETIME NULL,
    CONSTRAINT PK_HCM_Event_Log PRIMARY KEY CLUSTERED (id)
)

Тогда у меня были бы различные реляционные таблицы для таких вещей, как type_id и группировка элементов.

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

Мой вопрос

Это плохая или хорошая идея? Я понимаю, что в SQL Server (Standard r2 Standard Edition BTW) и в правилах «иногда» каждая ситуация различна, но я просто ищу общие советы.

Я начал рассматривать возможность использования сервисного брокера, но я буду выполнять только простые обновления / вставки ( см. Альтернативу принятому ответу ). Во многих случаях данные должны быть в реальном времени, поэтому использование резервной БД не будет работать. Производительность уже является для нас проблемой, но в основном это связано с аппаратным обеспечением, которое скоро будет решено.

jreed121
источник
1
Можете ли вы обеспечить выполнение запланированных отключений? Если ни одно из этих обновлений не может уничтожить триггер, и вы не будете обновлять свои агрегаты, что может привести к некорректным данным.
Эрик
Вы планируете поместить всю информацию о лабораториях, о процедурах, о вакцинах и о пациентах в одну таблицу? Плохая идея. Вы можете использовать схему типа «звезда», если она соответствует типу выполняемых вами запросов.
Майкл Грин
1
Вы смотрели на создание некоторых индексированных представлений? Это создаст логический уровень между вашим кодом и поставщиком, так что вы можете просто обновить представление, если поставщик изменит вещи под ним. Кроме того, индексированные представления будут предварительно заполнены для вас и обеспечат хорошую производительность чтения. Одним из самых важных соображений при этом является то, насколько сильно он загружает операции записи таблиц базы данных поставщика. Однако это, вероятно, будет более чистым и простым в обслуживании решением, чем использование триггеров и т. Д.
Мика Никкель
Извините за поздний ответ, ребята, спасибо за отзыв. @Erik - Да, мы запланировали обновления, и я проверяю, чтобы все мои предыдущие изменения все еще были в силе с помощью серии сценариев контрольного списка, которые я запускаю, чтобы не было никаких сюрпризов, и я оставлю сценарии CREATE для все триггеры.
jreed121
@MichaelGreen - Я посмотрю на звездную схему, но мне любопытно, почему вы думаете, что хранить все эти данные в одной таблице - плохая идея? Среда приложения полностью изолирована от VPN, в любом случае она недоступна вне сети. Если что-то пойдет не так с таблицей, то это не конец света, потому что я могу просто написать все обратно. Таблица не будет использоваться для критически важных данных, или, по крайней мере, она не будет единственным или основным местом хранения данных.
jreed121

Ответы:

8

Если я вас правильно понял,

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

Я хотел бы подойти к этому так:

  • Настройте мою собственную отдельную базу данных, которую я полностью контролирую.
  • Настройте процесс синхронизации, который считывает данные из соответствующих таблиц и столбцов из сторонней базы данных и вставляет / обновляет в мою.
  • Разработка моих сложных отчетов на основе стабильной структуры моей базы данных.

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

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

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

Обновить

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

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

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

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

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

Владимир Баранов
источник
Если вы идете по маршруту пакетной передачи, мы добились успеха с отслеживанием изменений (и изменением сбора данных, в зависимости от ваших потребностей) при довольно большом количестве транзакций (100 КБ в день). Это проще, чем реализация собственных таблиц промежуточного хранения / аудита / сравнения и может быть развернуто без изменения кода приложения или триггеров.
Майкл Грин
Будь то триггеры или CDC, единственный способ приблизиться к режиму реального времени - это потоковая передача или организация очередей. Основанный на очереди - хороший компромисс для задержки и эффективности затрат. Ваше время будет потрачено на методы, чтобы обработать очередь быстрее. оставляя большую часть работы асинхронной с приложением и уменьшая нагрузку на пользовательские транзакции. В прошлом я делал это против Allscripts Sunrise EMR с помощью сервиса, который обрабатывал очередь несколькими параллельными вызовами foreach C #. типичная задержка для новых данных, которые будут обработаны и доступны на складе, составляла менее 30 секунд
Брэд Д.
Возможно, я уже говорил «в режиме реального времени», я не слишком озабочен миллисекундами или даже 5 секундами, но у меня есть много запросов, на которые наши сотрудники полагаются для управления рабочим процессом. Если с клиентом что-то было сделано (процедура, иммунизация и т. Д.), Мы должны показать это в короткие сроки. Преобразования являются тривиальными, и / или даже не преобразованиями. Меня не слишком беспокоит изменение таблиц вендоров, так как они меняются не так часто, и мне все равно придется делать это сейчас, но я думал, что проще обновить / пересоздать один триггер, чем дюжину отчетов / запросов / СФС. Я запускаю проверки после каждого обновления.
jreed121
@ jreed121, я также думаю , что это легче обновление триггера (ов) , чем отчеты. Скорее всего, у вас будет триггер на каждой исходной таблице, чтобы зафиксировать изменения, так что, вероятно, это будет более одного триггера. Тем не менее, не пытайтесь записать все эти зафиксированные изменения в одну огромную денормализованную таблицу. Запишите их в правильно нормализованный набор таблиц. Ваши отчеты должны основываться на этих нормализованных таблицах, которые вы контролируете, и не должны зависеть от исходных таблиц, которые могут измениться.
Владимир Баранов
3

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

Как уже упоминали другие, не используйте триггеры, синхронизируйте в пакетном режиме.

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

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

JamesRyan
источник
3

В прошлом я работал с очень похожей ситуацией в производственной компании 24x7 и, наконец, решил использовать репликацию транзакций. Можно настроить репликацию DDL таким образом, чтобы вы могли распространять любые изменения, вносимые подписчику. Очевидно, что у каждого есть свои плюсы и минусы, и вам нужно взвесить их, чтобы определить, что вы можете поддержать, а что лучше всего подходит для компании.

С положительной стороны:

  1. «Реальное время» ограничено только эффективностью фиксации сети и транзакций на подписчике. По моему опыту с умеренно высокой системой TPS, мы были реплицированы с точностью до 10 секунд данных в режиме реального времени.
  2. Разделение рабочих нагрузок. В настоящее время вы работаете со смешанной нагрузкой на одном сервере. Если вы сможете отделить эти две проблемы, то вы сможете получить преимущества в производительности обеих систем, исключив одну рабочую нагрузку из уравнения.
  3. Контроль. Вы сможете вносить изменения в индексирование / статистику / обслуживание в соответствии с вашей рабочей нагрузкой.

Хотя есть и минусы:

  1. Стоимость. Другая лицензия и другое оборудование (виртуальное или иное).
  2. Репликация. Он прекрасно работает, как только он настроен правильно, но это может быть хлопот, чтобы добраться до этой точки.
  3. Техническое обслуживание. Если вы вносите какие-либо вредные изменения в структуры (например, удаляете индекс), они возвращаются при применении моментального снимка (после изменения публикации или после изменения статей).
swasheck
источник
2

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

Триггеры имеют так много проблем, что вы должны избегать их:

  • Ошибка в триггере может привести к прерыванию исходной транзакции
  • Триггеры, которые правильно обрабатывают многострочные операции, сложно написать
  • Триггеры могут запутать клиентские приложения, изменив возвращенный набор строк (например, триггер переопределяет количество затронутых строк)
  • Когда один триггер запускает другой, результаты трудно предсказать

Лучшим вариантом является задание, которое периодически копирует данные в новую таблицу. Ваши отчеты могут работать копии. Задание, которое копирует строки, легко написать и поддерживать, и нет риска, что это повлияет на работу стороннего приложения.

Andomar
источник
1. Триггеры будут простыми, поэтому сгенерированные ошибки будут минимальными, если вообще существуют. 2. Сам триггер не будет обрабатывать несколько строк (то есть одна строка, обновляемая в таблице с помощью триггера, не приведет к обновлению нескольких строк в другом месте), но несколько строк могут быть вставлены / обновлены / удалены одновременно в источнике стол - это ты о чем? 3. с этим нельзя справиться NOCOUNT? 4. В таблице назначения не было бы никаких триггеров, и я мог бы гарантировать то же самое для остальных.
jreed121
Как вы говорите, теоретически возможно заставить работать триггеры. Просто на практике они никогда не делают.
Андомар