我已经在“订单”表上实现了系统版本化临时表。应用程序使用不同的访问模式来修改此表中的数据。有来自应用程序的直接语句,或者应用程序在显式事务中运行长批处理,其中对多个表进行了多次更改。“订单”表上的更新不是那些长批次中的第一条语句!因此,有时我们会面临以下错误。
系统版本化表“Orders”上的数据修改失败,因为事务时间早于受影响记录的期间开始时间。
显然,这是系统版本化临时表的标准行为。https://docs.microsoft.com/en-us/sql/relational-databases/tables/temporal-tables?view=sql-server-2017#how-does-temporal-work
这是总是需要在异常例程中处理的东西吗?还是微软正在考虑改变这种行为?
-- 模拟错误信息的脚本:
CREATE TABLE dbo.Orders
(
[OrderId] INT NOT NULL PRIMARY KEY CLUSTERED
, [OrderValue] DECIMAL(19,4)
, [ValidFrom] DATETIME2 (2) GENERATED ALWAYS AS ROW START
, [ValidTo] DATETIME2 (2) GENERATED ALWAYS AS ROW END
, PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.OrdersHistory));
GO
INSERT dbo.Orders ([OrderId], [OrderValue])
VALUES (1, 9.99), (2, 9.99);
GO
SELECT * FROM dbo.Orders;
GO
--Run first query
BEGIN TRAN
WAITFOR DELAY '00:00:15';
UPDATE dbo.Orders
SET …Run Code Online (Sandbox Code Playgroud) 查询系统版本控制的时态表FOR system_time ALL似乎省略了开始时间和结束时间相等的行。
例如:
/* Create a simple system-versioned table */
CREATE TABLE [dbo].[svt_test](
[string] [VARCHAR](30) NOT NULL,
[validFrom] [DATETIME2](7) GENERATED ALWAYS AS ROW START NOT NULL,
[validTo] [DATETIME2](7) GENERATED ALWAYS AS ROW END NOT NULL,
CONSTRAINT [PK_svt_test] PRIMARY KEY CLUSTERED
(
[string] ASC
),
PERIOD FOR SYSTEM_TIME ([validFrom], [validTo])
)
WITH
(
SYSTEM_VERSIONING = ON ( HISTORY_TABLE = [dbo].[svt_test_history] )
);
/*
Insert and immediately delete a row.
May have to try multiple times to get a …Run Code Online (Sandbox Code Playgroud) 可能是一个非常简单的问题,但是FOR SYSTEM_TIME在查询时态表时使用语句时,有没有办法为历史表指定查询/表提示?我怀疑不是,但我想在放弃这个之前仔细检查一下。
这是一个dbfiddle,它显示了我所知道的为查询指定提示的不同方式的基本细分,我能弄清楚如何传递与历史表交互的查询和/或表提示的唯一方法是转换查询到UNION ALLlive 和 history 表之间,而不是使用FOR SYSTEM_TIME子句。
在使用该FOR SYSTEM_TIME子句时尝试指定历史表提示时,出现以下错误:
Msg 308 Level 16 State 1 Line X
Index '<<HISTORY TABLE INDEX NAME>>' on table '<<LIVE TABLE NAME>>' (specified in the FROM clause) does not exist.
Run Code Online (Sandbox Code Playgroud)
在使用该FOR SYSTEM_TIME子句时尝试指定指向历史记录表的查询提示时,出现以下错误:
Msg 8723 Level 16 State 1 Line X
Cannot execute query. Object '<<HISTORY TABLE>>' is specified in the TABLE HINT clause, but is not used in the query or does …Run Code Online (Sandbox Code Playgroud) 新版本的 SQL Server 2016 将支持所谓的Temporal Tables。
我找不到任何说明此功能是否仅适用于企业版或在标准版中可用的文档。
一方面,临时表注意事项和限制表明它将仅适用于企业:
- 默认情况下,历史表是 PAGE 压缩的。
- 最佳索引策略将包括聚集列存储索引 [...] 默认历史记录表具有聚集行存储索引
据我所知,数据压缩是企业独有的功能,但技术上标准版可以创建一个非压缩的历史表。
列存储索引是企业独有的功能,但默认情况下它会创建一个行存储索引,所以还是有希望的。
另一方面,sys.dm_db_persisted_sku_features 的文档在2014 年和 2016 年是相同的,并且企业功能列表没有临时表(也许文档还没有更新?)。
如果这个功能很有可能会被纳入标准版,我可以等半年,直到2016年发布,然后再将我的2008数据库迁移到最新版本。如果没有希望,我会将其迁移到 2014 年。如果我迁移到 2014 年,它可能会在接下来的 10 年中保留在此版本上。
关于搁置这个问题:
我不想要这个问题的“基于意见”的答案,我想知道事实。我本来希望这种信息会在某个地方发布,我只是不知道在哪里看。例如,直到今天我都不知道sys.dm_db_persisted_sku_features。
问题可以调整为:
如果不知道确凿的事实(尚未做出决定,甚至 SQL Server 开发人员也不知道),则根据先前版本中如何做出此决定进行有根据的猜测也很好。
有没有人试过用旧的历史数据预填充时态表?在我们决定使用时态表之前,我们需要能够将我们的旧历史导入其中。
我正在 SQL Server 中使用时态表,生成的时间是 UTC 中的事务开始时间datetime2。
SQL Server 中是否有一个函数或表可以获取相同的事务开始时间以在其他地方使用,而不需要我首先写入系统版本化表并从中进行选择?
我有一些非系统版本化表,它们是同一事务的一部分,并且我更希望记录的数据datetime2匹配,而不是使用SysUTCDateTime并使其变化。
我试图从中提取它,sys.dm_tran_active_transactions但它datetime和本地服务器时间似乎不同。
我们希望在 SQL Server 2016 中实现时态表。我们正在创建一个数据仓库并开发类型 2 缓慢变化的维度表。
对于 BeginDate,我们希望它取决于交易日期而不是当前的 getdate 时间。我们正在重新处理交易历史记录。下面的示例中,客户具有健身房或银行状态,并且根据交易日期从不活动状态变为活动状态或待处理状态。
我们目前有这个。
CREATE TABLE dbo.Department
(
CustomerId int primary key,
MembershipStatus int,
TransactionDate datetime
);
Run Code Online (Sandbox Code Playgroud)
我们想创建一个这样的表。
CREATE TABLE dbo.DepartmentHistory
(
CustomerId int primary key,
MembershipStatus int,
TransactionDate datetime,
BeginDatetime datetime,
EndDatettime datetime
);
Run Code Online (Sandbox Code Playgroud)
示例用法如下:
+------------+--------+------------+---------+
| 客户 ID | 状态 | 开始日期 | 结束日期 |
+------------+--------+------------+---------+
| 1 | 普 | 2018 年 3 月 5 日 | 空|
+------------+--------+------------+---------+
实际问题: sql 2019 服务器中是否有任何东西(除了触发器之外)可以导致在临时表中更新单行时在历史表中插入多行?
背景: 我有一个名为 Candidate 的现有表,它没有计算列,也没有触发器。我实现版本控制如下:
ALTER TABLE dbo.Candidate
ADD BeginDate datetime2 GENERATED ALWAYS AS ROW START NOT NULL DEFAULT SYSUTCDATETIME(),
EndDate datetime2 GENERATED ALWAYS AS ROW END NOT NULL DEFAULT CAST('9999-12-31 23:59:59.9999999' AS datetime2),
PERIOD FOR SYSTEM_TIME (BeginDate,EndDate)
GO
ALTER TABLE dbo.Candidate
SET(SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.Candidate_History, DATA_CONSISTENCY_CHECK = ON))
Run Code Online (Sandbox Code Playgroud)
当我对表进行更新时,即使是单个列( update候选集 lastContacted = '2021-10-16 23:27:46.927' where id = 44999 )也会有多行添加到历史表中:
| BeginDate | EndDate |
| --------- | ------- |
| 2022-01-24 08:25:55.3718538 | 2022-01-24 …Run Code Online (Sandbox Code Playgroud) Microsoft 文档当前在 ALTER TABLE 系统版本控制示例中给出了如何在现有表上启用临时表的示例:A. 将系统版本控制添加到现有表
使用那里的语法但指定一个常量默认值,我有:
ALTER TABLE InsurancePolicy
ADD PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo),
ValidFrom datetime2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL
-- DEFAULT SYSUTCDATETIME(), /* default specified in the docs */
DEFAULT CONVERT(DATETIME2, '2023-08-14') /* use a constant default */
ValidTo datetime2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL
DEFAULT CONVERT(DATETIME2, '9999-12-31 23:59:59.99999999') ;
Run Code Online (Sandbox Code Playgroud)
当我运行此语句时,我可以SP:StatementStarting使用 TextData 观察一个事件:SELECT [ValidFrom],[ValidTo] FROM [dbo].[InsurancePolicy]
这告诉我 SQL Server 正在查看该数据(可能是为了确定 ValidTo 和 ValidFrom 符合某些约束)。
模式修改锁+表扫描让我很伤心。
理论上,扫描是不必要的,因为这些值是恒定的。在 …
我有一个由外部公司开发的大型 PHP 应用程序,目前正在完成;我不能要求对其进行更改。它使用一个数据库 Microsoft SQL Server 2016,一些用户通过 SSMS 访问该数据库,包括我,以及在一天中的特定时间由一些计划任务访问。有时我会在一些表格中发现意想不到的内容,这很令人沮丧,因为我不知道它是什么时候到达的。我刚刚发现了时态表:知道记录更改的确切日期和时间将非常有用。
是否可以在应用程序中为 2-3 个关键表添加时态表,而无需更改 PHP 代码?是否存在兼容性或性能风险?