标签: temporal-tables

使用 SQL Server 2016 system-versioned temporal table for Slowly-Changed Dimensions 的查询策略

当使用系统版本控制的时态表(SQL Server 2016 中的新功能)时,当使用此功能处理大型关系数据仓库中的缓慢变化维度时,查询创作和性能影响是什么?

例如,假设我有一个Customer带有Postal Code列的 100,000 行维度和一个Sales带有CustomerID外键列的数十亿行事实表。并假设我想查询“按客户邮政编码划分的 2014 年总销售额”。简化的 DDL 是这样的(为了清楚起见省略了很多列):

CREATE TABLE Customer
(
    CustomerID int identity (1,1) NOT NULL PRIMARY KEY CLUSTERED, 
    PostalCode varchar(50) NOT NULL,
    SysStartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL, 
    SysEndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL,   
    PERIOD FOR SYSTEM_TIME (SysStartTime, SysEndTime) 
)
WITH (SYSTEM_VERSIONING = ON);

CREATE TABLE Sale
(
    SaleId int identity(1,1) NOT NULL PRIMARY KEY CLUSTERED,
    SaleDateTime …
Run Code Online (Sandbox Code Playgroud)

data-warehouse sql-server slowly-changing-dimension temporal-tables sql-server-2016

17
推荐指数
1
解决办法
1214
查看次数

错误 13542 为现有表启用系统版本控制

我正在尝试为包含数据的 SQL Server 2016 数据库中的某些现有表启用系统版本控制。我正在遵循Microsoft 的这些说明

其中一张表如下所示:

CREATE TABLE [dbo].[ClientBeacon](
    [ClientId] [int] NOT NULL,
    [BeaconId] [int] NOT NULL,
    [FromDate] [datetime] NOT NULL,
    [ToDate] [datetime] NULL,
    [Deleted] [bit] NOT NULL,
    [ModifiedByUserId] [nvarchar](128) NOT NULL,
    [ModifiedOn] [datetime] NOT NULL,
    [Timestamp] [timestamp] NOT NULL,
    CONSTRAINT [PK_ClientBeacon] PRIMARY KEY CLUSTERED 
    (
        [ClientId] ASC,
        [BeaconId] ASC
    )
)
Run Code Online (Sandbox Code Playgroud)

我试图运行的脚本如下所示:

CREATE SCHEMA History;   
GO

ALTER TABLE dbo.ClientBeacon   
   ADD   
      SysStartTime datetime2(0) GENERATED ALWAYS AS ROW START HIDDEN CONSTRAINT DF_ClientBeacon_SysStartTime DEFAULT SYSUTCDATETIME(),
      SysEndTime datetime2(0) GENERATED ALWAYS …
Run Code Online (Sandbox Code Playgroud)

sql-server temporal-tables sql-server-2016

10
推荐指数
1
解决办法
5466
查看次数

旧值的时态表性能不佳

我在访问时态表中的历史记录时遇到了一个奇怪的问题。通过 AS OF 子句访问临时表中较旧条目的查询比对最近历史条目的查询花费的时间更长。

历史表是由 SQL Server 生成的(包括日期列上的聚集索引并使用页面压缩),我向历史表添加了 5000 万行,我的查询检索了大约 25,000 行。

我试图确定问题的根本原因,但无法确定。到目前为止,我已经测试过:

  • 创建一个包含 5000 万行并带有聚集索引的测试表,以查看速度变慢是否仅仅是由于数量所致。我能够在恒定时间(~400 毫秒)检索 25K 行。
  • 从历史表中删除页面压缩。这对检索时间没有影响,但确实显着增加了表的大小。
  • 我尝试使用 ID 列与日期列直接访问历史记录表的行。这是事情更有趣的地方。我可以在 ~400 毫秒内访问表中较旧的行,而与 AS OF 子子句一样,它需要 ~1200 毫秒。我尝试在日期列上的测试表上进行过滤,并注意到与 ID 列上的过滤相比有类似的减速。这让我相信日期比较是一些放缓的原因。

我想多看看这个,但我也想确保我没有吠错树。首先,是否有其他人在访问时态表中的旧历史数据时遇到过同样的行为(我们只注意到速度超过 1000 万行)?其次,我可以使用哪些策略来进一步隔离性能问题的根本原因(我刚刚开始研究执行计划,但对我来说仍然有点神秘)?

执行计划

这些是简单的检索查询:第一个访问较旧的行,第二个访问较新的行。

较旧的行~1200 毫秒执行时间

最近行~350ms 执行时间

表详细信息

这些是时态表中的列。历史表具有相同的列但没有主键(根据历史表要求): 时态表列

以下是历史表上的索引: 历史表上的索引

performance sql-server temporal-tables

10
推荐指数
1
解决办法
3877
查看次数

临时表在没有时记录更改吗?

不幸的是,我没有准备好访问 SQL 2016 实例来测试这个。如果我有一个具有以下架构的时态表:

create table blah (
    foo int identity(1,1),
    baa int
)
Run Code Online (Sandbox Code Playgroud)

我要运行以下语句:

update blah set baa = baa
Run Code Online (Sandbox Code Playgroud)

它会像我实际更新数据一样记录更改吗?

我已经查看了MSDN 文章中的临时表修改数据的文章,但在那里找不到任何指定此内容的内容。

sql-server temporal-tables sql-server-2016

9
推荐指数
1
解决办法
1076
查看次数

为什么时态表会记录事务的开始时间?

更新时态表中的一行时,该行的旧值存储在历史表中,事务开始时间为SysEndTime. 当前表中的新值将事务开始时间作为SysStartTime

SysStartTimeSysEndTime是时datetime2态表用于记录某行何时是当前版本的列。事务开始时间是包含更新的事务开始的时间。

BOL 说:

系统 datetime2 列中记录的时间基于事务本身的开始时间。例如,在单个事务中插入的所有行都将在对应于 SYSTEM_TIME 周期开始的列中记录相同的 UTC 时间。

示例:我开始更新 Orders 表中的所有行,20160707 11:00:00事务运行需要 5 分钟。这会在历史记录表中为每一行创建一行SysEndTimeas 20160707 11:00:00。当前表中的所有行都有一个SysStartTimeof 20160707 11:00:00

如果有人在20160707 11:01:00(更新正在运行时)执行查询,他们将看到旧值(假设默认读已提交隔离级别)。

但是,如果有人然后使用AS OF语法来查询时态表,因为20160707 11:01:00他们会看到新值,因为他们SysStartTime将是20160707 11:00:00.

对我来说,这意味着它不会像当时那样显示这些行。如果它使用事务结束时间,则问题将不存在。

问题:这是设计使然吗?我错过了什么吗?

我认为它使用事务开始时间的唯一原因是它是事务开始时唯一的“已知”。它不知道事务开始时何时结束,并且在结束时应用结束时间需要时间,这会使它应用的结束时间无效。这有意义吗?

应该允许您重新创建问题。

transaction temporal-tables sql-server-2016

9
推荐指数
1
解决办法
2071
查看次数

SQL Server 2016:时态表性能与触发器和 CDC

似乎很难找到系统版本化时态表与旧选项(例如 DB 触发器和 CDC)之间的比较。我目前没有时间在 SQL Server 2016 上编写扩展测试,所以我想我会在这里问一下。

基本上,触发器的典型优势是它们在独立和集群/alwaysOn 环境中更易于管理,可以实时同步,并且可以访问会话数据,例如用户 ID。

另一方面,CDC 虽然需要更多的管理并且是异步的,但要得多,因此性能要好得多。因此,如果对触发器引起的瓶颈可能成为问题有任何疑问,CDC 基本上将是最佳解决方案。在硬件要求方面,由于使用日志和 cdc 审计表来跟踪更改,CDC 对额外空间的要求可以忽略不计。

问题:时态表与上述两个相比如何?在速度、性能、存储空间使用方面。何时应该使用时态表而不是触发器或 CDC?我什么时候不应该?

我理解任何可能复杂的事情,因为 DB 审计背后的业务需求和技术限制不会有一个简单的答案,因为它在很大程度上取决于项目的要求和范围。但是,如果能对上述问题有更多的了解,我们将不胜感激。谢谢!

2021年编辑:由于对此一直有一些兴趣,几年后我已经非常熟悉上述所有内容,这里是性能方面的简短摘要:我对 SQL Server 2016 的某个版本进行了测试,涉及插入、更新和删除10000 行来自 40 个不同类型的表一一列出,并绘制了每个表的总体时间、基本锁定信息等。简单的总结是,触发器平均为操作增加了 500-1000% 的延迟,而使用临时表和 CDC 时,每个操作的额外延迟接近 10%。如果我有确切的结果会有所帮助,但我不再记得它们了。触发过程非常简化,但每个更改的列插入一行,而 temporal / cdc 插入一行,而不管其中更改了多少列。在这个意义上,由于同时插入多行的键争用,一些更改可能使触发器看起来比它们更慢。然而,很明显触发器是最不适合简单审计的工具。所以这是我在创建这篇文章时试图理解的差异的简单技术概要:

触发器只有在你真的需要一些内置到数据库中的自定义逻辑时才有用,以监视 DML 更改,修改特定数据,在特定实例中捕获用户 ID 等。但尽量避免它们像瘟疫一样。他们的表现很糟糕。如果您需要审计或日志记录,它们是您应该查看的最后一个地方。

临时表一旦运行起来就非常容易管理,尤其是在像 Always On 这样的 HADR 中。由于它们支持压缩并反映从父表到历史表的大多数模式更改,因此它们需要很少的维护。特别是对于新的 SQL Server 版本,您可以设置保留期以删除超过 x 年的数据,因此存储和清理方面的考虑也可以忽略不计。它们就像事情来临时一样容易被遗忘,除非对需要更改数据的父表进行一些奇特的更新,在这种情况下,您必须取消链接,修改父表和历史记录表,然后再次链接它们。但这些都是罕见的,而且相对容易做到。时态表包很健壮,可以很好地处理错误,因此您会发现它很难被意外破坏。

然后,CDC 非常适用于报告服务或类似的场景,在这些场景中,您不介意异步数据,但您需要分析更改,例如每晚批处理。您可以将保留设置设置为仅保留 x 天的数据,以将存储成本降至最低。也就是说,根据我的经验,CDC 很挑剔而且不是很稳定。DML 有时会在没有警告的情况下“破坏”它,因此您可能需要数据库级 DDL 触发器来警告您 CDC 跟踪的对象发生了变化。您可能还需要为 HADR 设置自定义监视作业,因为它本身不处理故障转移事件。并且 CDC 有一个非常讨厌的倾向,即在被禁用后无法重新启动,这与使用 MS 自己的作业未正确更新它的状态有关。这意味着它偶尔需要手动工作以确保正确删除清理和捕获作业及其引用。也就是说,SSIS / RS 集成得非常好,使他们可以轻松使用 …

trigger sql-server change-data-capture temporal-tables sql-server-2016

9
推荐指数
1
解决办法
6861
查看次数

JOIN FOR SYSTEM TIME 以列作为有效系统时间

想象一下,我有一个模式,其中包括ProductsOrders,和OrderLineItems,与Products作为一个系统版本态表。

架构:

CREATE TABLE dbo.Products
(
    ProductID INT NOT NULL IDENTITY PRIMARY KEY,
    Name nvarchar(255) not null,
    SysStart DATETIME2 (7) GENERATED ALWAYS AS ROW START NOT NULL,
    SysEnd DATETIME2 (7) GENERATED ALWAYS AS ROW END NOT NULL,
    PERIOD FOR SYSTEM_TIME ([SysStart], [SysEnd])
)
WITH (SYSTEM_VERSIONING = ON(HISTORY_TABLE = dbo.Products_History, DATA_CONSISTENCY_CHECK = ON));
GO

CREATE TABLE dbo.Orders
(
    OrderID int not null identity primary key,
    OrderDate datetime2 (7) not null
);

CREATE TABLE …
Run Code Online (Sandbox Code Playgroud)

sql-server temporal-tables sql-server-2016

9
推荐指数
1
解决办法
4727
查看次数

在表上添加 PERIOD FOR SYSTEM_TIME 失败

我有:

  • 包含现有数据的表格
  • SQL Server 2016 SP1
  • SQL Server 管理工作室 17.5

我正在使用以下语句使我的表成为临时表:

ALTER TABLE [dbo].[AnalysisCustomRollupsV2JoinGroups]
ADD [SysStartTime] DATETIME2(0) GENERATED ALWAYS AS ROW START HIDDEN CONSTRAINT DF_AnalysisCustomRollupsV2JoinGroups_SysStart DEFAULT GETUTCDATE()  
   ,[SysEndTime] DATETIME2(0) GENERATED ALWAYS AS ROW END HIDDEN CONSTRAINT DF_AnalysisCustomRollupsV2JoinGroups_SysEnd DEFAULT CONVERT(DATETIME2(0), '9999-12-31 23:59:59'),   
PERIOD FOR SYSTEM_TIME ([SysStartTime], [SysEndTime]); 

ALTER TABLE [dbo].[AnalysisCustomRollupsV2JoinGroups]   
SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.AnalysisCustomRollupsV2JoinGroupsChanges));
Run Code Online (Sandbox Code Playgroud)

问题:

在我的本地 SQL 实例上,我有很多数据库;查询在其中一些上成功运行非常奇怪,而在其中一些上它给了我以下错误:

消息 13542,级别 16,状态 0,第 51 行 ADD PERIOD FOR SYSTEM_TIME 在表 'dbo.AnalysisCustomRollupsV2JoinGroups' 上失败,因为有打开的记录,期间的开始时间设置为将来的某个值。

有时,当我调试/执行查询时,初始查询运行成功。

我读到,这可能是因为我在表中有现有数据。所以,我改变了这样的逻辑:

  • 创建缓冲表并用所有记录填充它
  • 删除原表中的记录
  • 创建时态表
  • 将记录移回并删除缓冲表

再说一次,在某些数据库上它是可以的,而在其他数据库上则不是。试图解决这个问题,我 …

sql-server t-sql temporal-tables sql-server-2016

9
推荐指数
1
解决办法
6845
查看次数

为什么我有多个(未关联的)时间历史表?

我一直在建立一个具有 SQL Server 2017 后端的概念验证系统。
系统使用临时表来记录资产配置并跟踪随时间的变化。
我有一个链接到历史记录表的数据表,我们称之为 dbo.MSSQL_TemporaryHistoryFor_12345678900。

到现在为止还挺好。我有两个问题:

今天我关闭了表格上的版本控制,所以我可以添加一个计算列。这已完成并再次打开,没有错误。

现在我发现我无法查询更改之前的任何历史数据。新数据正在添加到历史记录中,但事先什么也没有。

查看 SSMS 内部,我现在可以看到有多个历史记录表,它们都具有相同的名称但带有十六进制后缀,例如 dbo.MSSQL_TemporaryHistoryFor_12345678900_A0B1C2D3。它们未链接到主数据表下方。它们只是在数据库中自行浮动。当我查询 sys.tables 时,这些没有显示为历史表,也没有链接到主数据表。

这些表确实包含缺失的历史数据。

因此,我的问题是:

  • 这些额外的表代表什么?
  • 它们是如何创建的?
  • 有没有办法以某种方式将这些重新链接到主历史链中,以便我可以取回我的历史报告?

这非常令人沮丧,因此我们将不胜感激地收到您能提供的任何帮助。谢谢。

sql-server temporal-tables sql-server-2017

8
推荐指数
1
解决办法
480
查看次数

SQL Server 的时态表会继续存在吗?

我们正在考虑在应用程序中保存记录历史的不同方法。

部分负责人担心,这是SQL server比较新的特性,微软可能会停止支持。

这些担忧是否合理?
是否有此功能的路线图,说明 Microsoft 打算在未来使用此功能做什么?

sql-server temporal-tables

8
推荐指数
2
解决办法
1170
查看次数