Eu tenho uma tabela que armazena informações do cliente (seu material de CRM padrão do pântano):
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 ''
)
Esta tabela foi recentemente convertida em uma tabela temporal do 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 )
)
Desde que isso aconteceu, um problema surgiu: o formulário voltado para o usuário que os usuários editam os detalhes do cliente salva automaticamente o conteúdo do formulário 2 segundos após o último pressionamento de tecla, e cada salvamento resulta em uma UPDATE
instrução com quantidades de dados cada vez maiores - e assim SQL Server está constantemente adicionando novas linhas à Customers_History
tabela, com 2 segundos de intervalo, o que resulta em linhas com poucas informações e spam.
Então é isso que eu vejo quando faço um SELECT * FROM dbo.Customers_History WHERE CustomerId = 123
, por exemplo:
Eu estava pensando que o código do lado do servidor que lida com os envios de salvamento automático poderia verificar se o estado do formulário de entrada é uma alteração incremental e, em caso afirmativo, UPDATE
a dbo.Customers
tabela sem adicionar nenhuma linha à Customers_History
tabela.
Até agora, a única maneira que vejo para fazer isso é definindoSYSTEM_VERSIONING = OFF
dentro de uma transação, no entanto, tenho algumas dúvidas antes de realmente implementar isso ...
Embora a documentação diga (até recomende) a execução
ALTER TABLE dbo.Customers SET (SYSTEM_VERSIONING = OFF);
dentro de uma transação, ela não diz como isso afetaria outros usuários e conexões simultâneos . Afinal, esta é uma instrução DML, e as instruções DML têm comportamento inconsistente (hah!) com isolamento.Iniciar e concluir uma transação em um
PROCEDURE
lote armazenado ou SQL é uma coisa - mas determinar se umUPDATE
é realmente incremental ou não pode exigir alguma lógica de código de aplicativo personalizado, o que significa ter que iniciar e confirmar a transação a partir do código de aplicativo, o que parece uma má ideia por causa das milhares de coisas que agora podem dar errado , sem falar nos problemas de desempenho (neste caso, a latência da rede do servidor de aplicativos para o servidor de banco de dados deve ser inferior a 1 ms, mas isso ainda afetará a escalabilidade ).
Supondo que eu possa fazer isso em um PROCEDURE
, este código abaixo está correto e ele será dimensionado?
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
... mas isso não parece certo para mim - porque isso é basicamente a mesma coisa que hackear restrições adiáveis com ALTER TABLE dbo.Customers NOCHECK CONSTRAINT ALL
.