背景
我为大型健康记录数据库编写了很多大型报告,并且通常维护大型健康记录数据库(编写 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)
)
Run Code Online (Sandbox Code Playgroud)
然后我会有各种关系表,比如 type_id 和项目分组。
我开始重新猜测这个想法,因为其中有几个表被写入了相当多的内容,我要编写的 SP 和报告也会引用很多数据。所以我担心这个表会成为具有如此多 I/O 的记录锁定和性能噩梦。
我的问题
是坏主意还是好主意?我意识到 SQL Server(2008 r2 标准版 BTW)和“有时”规则中的每种情况都不同,但我真的只是在寻找一般建议。
我开始考虑使用服务代理,但我只会执行简单的更新/插入(请参阅已接受答案的替代方法)。在许多情况下,数据需要是实时的,因此使用备份 DB 不会真正起作用。性能对我们来说已经是一个问题,但其中大部分与硬件相关,很快就会得到解决。
我的公司使用一个软件套件,其中我唯一可以真正修改的是数据库。我们一直有性能问题(主要是我们希望尽快解决的硬件问题),但最近在特定区域特别糟糕 - 当它应该小于 5 时加载需要 20-120 秒。我承担了一些用户,在他们(和我的)机器上进行了跟踪,这似乎是有问题的查询:
SELECT s.create_timestamp, s.create_timestamp, s.create_timestamp_tz, s.row_timestamp, log_msg, pre_mod, post_mod, u.first_name, u.mi, u.last_name, log_id
FROM log_events s (NOLOCK), user_mstr u (NOLOCK)
WHERE s.organization_id = '00001'
AND source1_id = @account_id --Place holder for a client account unique id
AND source2_id IS NULL
AND source3_id IS NULL
AND source4_id IS NULL
AND s.created_by = u.user_id
Run Code Online (Sandbox Code Playgroud)
我知道 NOLOCK很糟糕,但我无法控制。
它仅在每个新 source1_id 的第一次滞后 - 之后的每次执行都更快 - 而且随着行数的增加,情况似乎变得更糟。我使用尚未运行的 source1_id 手动运行查询SET STATISTICS IO/TIME ON,它返回了中小行数(490),结果如下:
Table 'user_mstr'. Scan count 0, …Run Code Online (Sandbox Code Playgroud)