将来自不同表的数据聚合到一个表中是不明智的做法吗?


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和报告也将大量引用数据。因此,我担心此表将成为具有这么多I / O的记录锁定和性能噩梦。

我的问题

是个好主意?我意识到SQL Server(2008 r2 Standard Edition BTW)和“有时”规则中的每种情况都是不同的,但是我实际上只是在寻找一般建议。

我开始考虑使用服务代理,但是我只会执行简单的更新/插入(请参阅已接受答案的替代方法)。在许多情况下,数据需要是实时的,因此使用备份数据库是行不通的。性能对我们来说已经是一个问题,但其中大多数与硬件相关,将很快得到解决。


1
您可以执行计划内的停机吗?如果这些更新之一无法消除触发器,那么您将不会更新聚合,可能会导致数据损坏。
Erik

您正在考虑将有关实验室,程序,疫苗和患者的所有信息放在一个表中吗?馊主意。如果适合您正在运行的查询类型,则可以使用星型模式。
Michael Green

1
您是否考虑过创建一些索引视图?这些将在您的代码和供应商的代码之间放置一个逻辑层,因此,只要供应商更改了底层内容,您就可以更新视图。此外,索引视图将为您预先填充,并提供良好的读取性能。这样做的更大考虑因素之一是,它将对供应商的数据库表的写操作造成多少负载。然而,这很可能是一个更清洁,更易于维护的解决方案比使用触发器等
弥Nikkel

抱歉,回复晚了,谢谢您的反馈。@Erik-是的,我们已经计划了更新,我将通过运行的一系列清单脚本检查所有以前的更改是否仍然存在,因此不会有任何意外,因此我将保留CREATE脚本所有触发器。
jreed121

@MichaelGreen-我将研究星型模式,但是我很好奇为什么您认为将所有数据都放在一个表中是一个坏主意?应用程序环境完全隔离在VPN上,无论如何都无法在网络外部访问它。如果表出了问题,那不是世界末日,因为我可以将所有内容写回到表上。该表将不会用于关键任务数据,或者至少它不会成为存储数据的唯一或主要位置。
jreed121

Answers:


8

如果我对你的理解正确,

  • 您有大型的第三方系统,
  • 您对此没有太多控制权,
  • 您制作了直接从该第三方数据库读取数据的复杂报告,
  • 您的查询取决于第三方数据库的内部结构。

我会这样处理:

  • 设置我自己的独立数据库,该数据库我可以完全控制。
  • 设置一个同步过程,该过程从第三方数据库的相关表和列中读取数据,并将其插入/更新到我的数据库中。
  • 根据数据库的稳定结构开发复杂的报表。

在这种情况下,您可以微调数据库的结构和索引,以提高报告的性能,而不会影响第三方系统。除非原始数据结构发生重大变化,否则如果第三方数据库发生更改,则查询报表的逻辑将不会更改。您只需要调整同步过程。

同步过程实际上是转换过程-您将数据从第三方数据库转换为所需的结构。此转换过程的一部分可能是解决原始第三方数据库可能存在的任何规范化问题。只有系统的这一部分才需要了解并依赖第三方系统的内部结构。您的主要报告和主要查询将仅取决于您的数据库。

因此,主要要点是-分离并限制依赖于第三方系统内部的系统部分。

更新

关于实时性要求。顺便说一句,我一直认为“实时”的定义是“保证的响应时间”,而不是“一些小的响应时间”。当然,这取决于您的应用程序。在我的实践中,如果我在一分钟内检测到更改就同步两个数据库就足够了。如果用户在屏幕上看到报告并且某些基础数据发生了变化,则必须以某种方式重新运行该报告以反映此更改。您可以轮询更改或收听某些事件/消息,但仍必须再次执行报告查询以显示最新更改。

您已经打算编写触发器以捕获原始表中的更改并将这些更改写入一个通用表。因此,请按预期捕获更改,但将其写入适当规范化的表中,而不要写入单个表中。

因此,这是极端情况-将第三方数据结构转换为内部数据结构是在触发INSERT/UPDATE/DELETE第三方表的触发器中执行的。这可能很棘手。触发器的代码将取决于两个系统的内部结构。如果转换很简单,则可能会将原始延迟INSERT/UPDATE/DELETE到失败的地步。如果触发器中存在错误,则可能会影响原始事务,直至失败。如果第三方系统发生更改,则可能会中断您的触发器,从而导致第三方系统的事务失败。

不太极端的情况。为了使触发器的代码更简单,更不易出错,将所有捕获的更改写入一些登台/审核/差异表,设置一些标志/发送一条消息,指出有待更改,并启动将要进行的主转换过程通过这些中间表并执行转换。这里的主要问题是,潜在的繁重转换过程应发生在原始事务处理范围之外。

乍一看,它看起来很像您在问题中的原始建议。但是,不同之处在于:所有捕获表仅临时保存数据;数据量很小-发生了什么变化;它不必是单个表;最终,数据将存储在单独的经过适当规范化的永久表中,您可以完全控制这些表,这些表独立于第三方系统,并且可以针对查询进行调整。


如果您采用批量转移路线,我们已经以非常高的交易次数(每天10万笔)成功进行了变更跟踪(和变更数据捕获,具体取决于您的需求)。它比实现自己的登台/审核/差异表要简单,并且可以在不更改应用程序代码或触发器的情况下进行部署。
Michael Green

无论是触发器还是CDC,您真正接近实时的唯一方法就是流式传输或排队。基于队列是延迟和成本效益的良好折衷。您的时间将花在更快处理队列的方法上。使得大部分工作与应用程序保持异步,并减轻了用户事务的负担。过去,我通过使用服务通过一些并行的foreach C#调用处理队列的服务对Allscripts Sunrise EMR进行了此操作。待处理并在仓库中可用的新数据的典型延迟时间
Brad D

我可能已经说过“实时”,我不太关心毫秒甚至5秒,但是我有很多查询需要我们的员工来推动工作流程。如果服务对象对他们做了一些事情(手术,免疫等),我们需要在短时间内证明这一点。转化是微不足道的,和/或什至不是转化。我并不太担心供应商表的更改,因为它们不经常更改,现在无论如何我都必须这样做,但是我认为更新/重新创建一个触发器比十几个报告/查询要容易得多。 / SP。每次更新后我都会运行检查。
jreed121

@ jreed121,我也认为这比较容易触发更新(S)比报告。您可能在每个源表上都有一个触发器来捕获更改,因此它可能不止一个触发器。不过,不要尝试将所有捕获的更改写入一个巨大的非规范化表中。将它们写入一组正确归一化的表中。您的报告应该根据自己控制并应将这些规范化的表依赖于可能会改变原来的表。
弗拉基米尔·巴拉诺夫

3

务必将其放入一组标准化的表中,以便您可以调整导入阶段,而不必更改复杂的报告和查询。但是数据仍然应该规范化,这将需要多个表(但具有良好的索引)。

正如其他人提到的,不要使用触发器,而是要批量同步。

不必担心大量的联接,当对数据进行规范化和正确索引时,这些联接不会增加任何显着的成本或管理负担。

将规范化为数据仓库之类的时候就是您需要对无法预测的数据进行大量不同类型的查询的时候。它有其自身的缺点和开销,应在适当的地方使用,而不是一成不变的事情。


3

过去,我在一家24x7的制造公司中曾遇到过类似情况,最终决定使用事务复制。可以配置要复制的DDL,以便您可以将任何补丁更改推送给订户。显然,一切都各有利弊,您需要权衡它们,以确定可以提供哪些支持以及对公司最有效的支持。

在积极方面:

  1. “实时”仅限于订户上的网络和事务提交性能。根据我对中等TPS系统的经验,我们被复制到了不到10秒的“实时”数据中。
  2. 工作负载分离。您当前在一台服务器上运行混合工作负载。如果您可以将这两个问题分开,则可以从等式中删除一个工作负载,从而在两个系统上都能获得性能优势
  3. 控制。您将能够修改索引/统计/维护以适合您的报告工作量。

有缺点,但是:

  1. 成本。另一个许可证和更多硬件(虚拟或其他)。
  2. 复制。正确设置后,它会很好用,但要达到这一点可能会很麻烦。
  3. 保养。如果对结构进行了有害的更改(例如,删除索引),则它们将在应用快照时(在更改发布后或更改文章时)返回。

2

我的计划是将所有这些记录写入一个“全部捕获”表,并在原始表上写入触发器以维护该聚合表中的记录。

触发器有很多问题,您应避免使用它们:

  • 触发器中的错误可能导致原始事务中止
  • 难以正确处理多行操作的触发器
  • 触发器可以通过修改返回的行集来混淆客户端应用程序(例如,触发器会覆盖受影响的行数)
  • 当一个触发条件触发另一个触发条件时,结果很难预测

更好的选择是定期将数据复制到新表的作业。您的报告可以运行该副本。复制行的作业易于编写和维护,并且不会影响第三方应用程序的操作。


1.触发器将很简单,因此,如果存在的话,抛出的错误将很小。2.触发器本身不会处理多行(即在表中用触发器更新的一行不会导致多行在其他地方更新),但是可以在源中一次插入/更新/删除多行表-这是什么意思?3.不能处理NOCOUNT吗?4.目标表上不会有任何触发器,我可以确保其他触发器也是如此。
jreed121

就像您说的那样,在理论上使触发器起作用是可能的。只是在实践中他们从不这样做。
Andomar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.