我有一个存储客户信息的表格(您的标准 CRM 资料):
CREATE TABLE dbo.Customers (
TenantId int NOT NULL,
CustomerId int NOT NULL,
FirstName nvarchar(50) NOT NULL DEFAULT '',
LastName nvarchar(50) NOT NULL DEFAULT '',
CompanyName nvarchar(50) NOT NULL DEFAULT '',
Notes nvarchar(4000) NOT NULL DEFAULT ''
)
该表最近被转换为 SQL Server 时态表:
ALTER TABLE dbo.Customers
ADD COLUMN
SysStart datetime2(7) GENERATED ALWAYS AS ROW START NOT NULL,
SysEnd datetime2(7) GENERATED ALWAYS AS ROW END NOT NULL;
GO
ALTER TABLE dbo.Customers WITH (
PERIOD FOR SYSTEM_TIME ( SysStart, SysEnd ),
SYSTEM_VERSIONING = ON ( HISTORY_TABLE = dbo.Customers_History )
)
由于这样做,出现了一个问题:用户编辑客户详细信息的面向用户的表单会在最后一次击键后 2 秒自动保存表单内容,并且每次保存都会导致UPDATE
数据量递增的语句 - 因此 SQL Server不断向Customers_History
表中添加新行,相隔 2 秒,这会导致垃圾邮件、低信息行。
所以这就是我在做 a 时看到的SELECT * FROM dbo.Customers_History WHERE CustomerId = 123
,例如:
我在想处理自动保存提交的服务器端代码可以检查传入的表单状态是否是增量更改,如果是,UPDATE
则dbo.Customers
表不添加任何行到Customers_History
表中。
到目前为止,我能看到的唯一方法是SYSTEM_VERSIONING = OFF
在事务中设置,但是在我实际实现之前我有一些问题......
虽然文档说(甚至建议)
ALTER TABLE dbo.Customers SET (SYSTEM_VERSIONING = OFF);
在事务中运行,但没有说明这将如何影响其他并发用户和连接。毕竟这是一个 DML 语句,并且 DML 语句具有不一致的(哈哈!)行为 wrt 隔离。在存储
PROCEDURE
或 SQL 批处理中启动和完成事务是一回事 - 但确定一个UPDATE
是否实际上是增量的可能需要一些自定义应用程序代码逻辑,这意味着必须从应用程序代码启动和提交事务,这看起来像一个坏主意,因为现在有成千上万的事情可能出错,更不用说性能问题了(在这种情况下,从应用程序服务器到数据库服务器的网络延迟应该小于 1ms,但这仍然会影响可伸缩性)。
假设我可以在 a 中做到这一点PROCEDURE
,下面的代码是否正确,它会扩展吗?
CREATE PROCEDURE dbo.UpdateSingleCustomerRow(
@tenantId int,
@customerId int,
@firstName nvarchar(50),
@lastName nvarchar(50),
@companyName nvarchar(50),
@notes nvarchar(4000)
)
BEGIN TRY
BEGIN TRANSACTION editCustomerTxn;
SET XACT_ABORT ON;
-- Is it an incremental change?
DECLARE @isIncremental bit = 0;
IF EXISTS( SELECT 1 FROM dbo.Customers WHERE
CustomerId = @customerId
AND
TenantId = @tenantId
AND
CHARINDEX( FirstName, @firstName ) > 0
AND
CHARINDEX( LastName, @lastName ) > 0
AND
CHARINDEX( CompanyName, @companyName ) > 0
AND
CHARINDEX( Notes, @notes ) > 0
)
BEGIN
SET @isIncremental = 1;
END
-----------------------
IF @isIncremental = 1
BEGIN
ALTER TABLE dbo.Customers SET ( SYSTEM_VERSIONING = OFF );
END
UPDATE
dbo.Customers
SET
FirstName = @firstName,
LastName = @lastName,
CompanyName = @companyName,
Notes = @notes
WHERE
CustomerId = @customerId
AND
TenantId = @tenantId;
IF @isIncremental = 1
BEGIN
ALTER TABLE dbo.Customers SET (
SYSTEM_VERSIONING = ON(
HISTORY_TABLE = dbo.Customers_History
)
);
END
COMMIT TRANSACTION editCustomerTxn;
RETURN 0;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
BEGIN
ROLLBACK TRANSACTION editCustomerTxn;
END
RETURN 1;
END CATCH
...但这对我来说感觉不对- 因为这与使用ALTER TABLE dbo.Customers NOCHECK CONSTRAINT ALL
.