Criar uma tabela temporal com controle de versão do sistema
Aplica-se a: SQL Server 2016 (13.x) e versões posteriores
Banco de Dados SQL do Azure
Instância Gerenciada de SQL do Azure
Há três maneiras de criar uma tabela temporal com controle da versão do sistema ao considerar o modo como a tabela de histórico é especificada:
Tabela temporal com uma tabela de histórico anônimo: especifique o esquema da tabela atual e deixe o sistema criar a tabela de histórico correspondente com o nome gerado automaticamente.
Tabela temporal com uma tabela de histórico padrão: especifique o nome do esquema de tabela de histórico e o nome da tabela e deixe o sistema criar tabela de histórico nesse esquema.
Tabela temporal com uma tabela de histórico definida pelo usuário criada antecipadamente: crie a tabela de histórico que melhor atenda às suas necessidades e faça referência a essa tabela durante a criação da tabela temporal.
Criar uma tabela temporal com uma tabela de histórico anônimo
Criar uma tabela temporal com uma tabela de histórico "anônimo" é uma opção conveniente para a criação rápida de objeto, especialmente em ambientes de teste e de protótipos. Também é a maneira mais simples de criar uma tabela temporal, pois ela não requer nenhum parâmetro na SYSTEM_VERSIONING
cláusula . No exemplo a seguir, uma nova tabela é criada com o controle de versão do sistema habilitado sem definir o nome da tabela de histórico.
CREATE TABLE Department
(
DeptID INT NOT NULL PRIMARY KEY CLUSTERED,
DeptName VARCHAR(50) NOT NULL,
ManagerID INT NULL,
ParentDeptID INT NULL,
ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL,
ValidTo DATETIME2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
)
WITH (SYSTEM_VERSIONING = ON);
Comentários
Uma tabela temporal com versão do sistema deve ter uma chave primária definida e ter exatamente uma
PERIOD FOR SYSTEM_TIME
definida com duas colunas datetime2 , declaradas comoGENERATED ALWAYS AS ROW START
ouGENERATED ALWAYS AS ROW END
.As
PERIOD
colunas sempre são consideradas não anuláveis, mesmo que a nulidade não seja especificada. Se asPERIOD
colunas forem definidas explicitamente como anuláveis, aCREATE TABLE
instrução falhará.A tabela de histórico sempre deve estar alinhada ao esquema com a tabela atual ou temporal, em relação ao número de colunas, nomes de colunas, ordenação e tipos de dados.
Uma tabela de histórico anônimo é criada automaticamente no mesmo esquema que a tabela temporal ou atual.
O nome da tabela de histórico anônima tem o seguinte formato: MSSQL_TemporalHistoryFor_<current_temporal_table_object_id>_[sufixo]. O sufixo é opcional e é adicionado somente se a primeira parte do nome da tabela não for exclusiva.
A tabela de histórico é criada como uma tabela rowstore. A compactação PAGE é aplicada, se possível, caso contrário, a tabela de histórico é descompactada. Por exemplo, algumas configurações de tabela, como as colunas ESPARSAS, não permitem a compactação.
Um índice clusterizado padrão é criado para a tabela de histórico com um nome gerado automaticamente no formato IX_<history_table_name>. O índice clusterizado contém as
PERIOD
colunas (end, start).Para criar a tabela atual como uma tabela com otimização de memória, consulte Tabelas temporais com controle da versão do sistema com tabelas com otimização de memória.
Criar uma tabela temporal com uma tabela de histórico padrão
A criação de uma tabela temporal com uma tabela de histórico padrão é uma opção conveniente quando você deseja controlar a nomenclatura e ainda depende do sistema para criar a tabela de histórico com a configuração padrão. No exemplo a seguir, uma nova tabela é criada com o controle de versão do sistema habilitado com o nome da tabela de histórico explicitamente definido.
CREATE TABLE Department
(
DeptID INT NOT NULL PRIMARY KEY CLUSTERED,
DeptName VARCHAR(50) NOT NULL,
ManagerID INT NULL,
ParentDeptID INT NULL,
ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL,
ValidTo DATETIME2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.DepartmentHistory));
Comentários
A tabela de histórico é criada usando as mesmas regras que se aplicam à criação de uma tabela de histórico "anônimo", com as seguintes regras se aplicam especificamente à tabela de histórico nomeada.
- O nome do esquema é obrigatório para o
HISTORY_TABLE
parâmetro . - Se o esquema especificado não existir, a
CREATE TABLE
instrução falhará. - Se a tabela especificada pelo
HISTORY_TABLE
parâmetro já existir, ela será validada em relação à tabela temporal recém-criada em termos de consistência de esquema e consistência de dados temporais. Se você especificar uma tabela de histórico inválida, aCREATE TABLE
instrução falhará.
Criar uma tabela temporal com uma tabela de histórico definida pelo usuário
A criação de uma tabela temporal com uma tabela de histórico definida pelo usuário é uma opção conveniente quando o usuário deseja especificar a tabela de histórico com opções de armazenamento específicas e índices diferentes ajustados às consultas históricas. No exemplo a seguir, uma tabela de histórico definida pelo usuário é criada com um esquema alinhado com a tabela temporal criada. Para esta tabela de histórico definida pelo usuário, um índice columnstore clusterizado e um índice rowstore não clusterizado adicional (árvore B+) são criados para pesquisas de ponto. Após a criação dessa tabela de histórico definido pelo usuário, a tabela temporal com controle da versão do sistema é criada especificando a tabela de histórico definido pelo usuário como a tabela de histórico padrão.
CREATE TABLE DepartmentHistory
(
DeptID INT NOT NULL,
DeptName VARCHAR(50) NOT NULL,
ManagerID INT NULL,
ParentDeptID INT NULL,
ValidFrom DATETIME2 NOT NULL,
ValidTo DATETIME2 NOT NULL
);
GO
CREATE CLUSTERED COLUMNSTORE INDEX IX_DepartmentHistory ON DepartmentHistory;
CREATE NONCLUSTERED INDEX IX_DepartmentHistory_ID_Period_Columns ON DepartmentHistory (
ValidTo,
ValidFrom,
DeptID
);
GO
CREATE TABLE Department
(
DeptID int NOT NULL PRIMARY KEY CLUSTERED,
DeptName VARCHAR(50) NOT NULL,
ManagerID INT NULL,
ParentDeptID INT NULL,
ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START NOT NULL,
ValidTo DATETIME2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.DepartmentHistory));
Comentários
- Se você planeja executar consultas analíticas em dados históricos que empregam agregações ou funções de janelamento, a criação de uma columnstore clusterizada como um índice primário é altamente recomendável para o desempenho da consulta e compactação.
- Se o caso de uso principal for a auditoria de dados (ou seja, pesquisa por alterações históricas de uma única linha da tabela atual), uma boa opção será criar uma tabela de histórico de rowstore com um índice clusterizado
- A tabela de histórico não pode ter chave primária, chaves estrangeiras, índices exclusivos, restrições de tabela ou gatilhos. Ela não pode ser configurada para captura de dados de alterações, controle de alterações ou replicação de mesclagem ou transacional.
Alteração de tabela não temporal para tabela temporal com controle da versão do sistema
Você pode habilitar o controle de versão do sistema em uma tabela não temporal existente, como quando você deseja migrar uma solução temporal personalizada para suporte interno. Por exemplo, você pode ter um conjunto de tabelas nas quais o controle de versão é implementado com gatilhos. O uso do controle de versão do sistema temporal é menos complexo e oferece outros benefícios que incluem:
- Histórico imutável
- Nova sintaxe para consultas entre períodos
- Melhor desempenho de DML
- Custos mínimos de manutenção
Ao converter uma tabela existente, considere usar a HIDDEN
cláusula para ocultar as novas PERIOD
colunas (as colunas ValidFrom
datetime2 e ValidTo
) para evitar afetar aplicativos existentes que não especificam explicitamente nomes de coluna (por exemplo, SELECT *
ou INSERT
sem lista de colunas) não foram projetados para lidar com novas colunas.
Adição do controle de versão a tabelas não temporais
Se você quiser começar a controlar as alterações de uma tabela não temporal que contenha os dados, precisará adicionar a PERIOD
definição e, opcionalmente, fornecer um nome para a tabela de histórico vazia que SQL Server cria para você:
CREATE SCHEMA History;
GO
ALTER TABLE InsurancePolicy
ADD
ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN
CONSTRAINT DF_InsurancePolicy_ValidFrom DEFAULT SYSUTCDATETIME(),
ValidTo DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN
CONSTRAINT DF_InsurancePolicy_ValidTo DEFAULT CONVERT(DATETIME2, '9999-12-31 23:59:59.9999999'),
PERIOD FOR SYSTEM_TIME(ValidFrom, ValidTo);
GO
ALTER TABLE InsurancePolicy
SET (SYSTEM_VERSIONING = ON (HISTORY_TABLE = History.InsurancePolicy));
GO
Importante
A precisão para DATETIME2
deve se alinhar com a precisão da tabela subjacente. Confira as observações a seguir.
Comentários
- Adicionar colunas não anuláveis com padrões a uma tabela existente com dados é um tamanho de operação de dados em todas as edições que não sejam SQL Server Enterprise edição (na qual é uma operação de metadados). Com uma grande tabela de histórico existente com dados em SQL Server Standard edição, adicionar uma coluna não nula pode ser uma operação cara.
- As restrições para colunas com período de início e período de término devem ser escolhidas com cuidado:
- O padrão para a coluna inicial especifica a partir de qual ponto no tempo você considera as linhas existentes válidas. Isso não pode ser especificado como um ponto de datetime no futuro.
- A hora de término precisa ser especificada como o valor máximo para determinada precisão de datetime2, por exemplo,
9999-12-31 23:59:59
ou9999-12-31 23:59:59.9999999
.
- Adicionar
PERIOD
executa uma consistência de dados marcar na tabela atual para garantir que os valores existentes para colunas de período sejam válidos. - Quando uma tabela de histórico existente é especificada ao habilitar
SYSTEM_VERSIONING
, uma consistência de dados marcar é executada na tabela atual e no histórico. Ele poderá ser ignorado se você especificarDATA_CONSISTENCY_CHECK = OFF
como um parâmetro adicional.
Migrar as tabelas existentes para o suporte interno
Este exemplo mostra como migrar de uma solução existente com base em gatilhos para o suporte temporal interno. Para este exemplo, vamos supor que a solução personalizada atual divide os dados atuais e históricos em duas tabelas de usuário separadas (ProjectTaskCurrent
e ProjectTaskHistory
).
Se a solução existente usa uma só tabela para armazenar as linhas reais e históricas, divida os dados entre duas tabelas antes das etapas de migração mostradas no exemplo a seguir. Primeiro, solte o gatilho na tabela temporal futura. Em seguida, verifique se as PERIOD
colunas são não anuláveis.
/* Drop trigger on future temporal table */
DROP TRIGGER ProjectCurrent_OnUpdateDelete;
/* Make sure that future period columns are non-nullable */
ALTER TABLE ProjectTaskCurrent
ALTER COLUMN [ValidFrom] DATETIME2 NOT NULL;
ALTER TABLE ProjectTaskCurrent
ALTER COLUMN [ValidTo] DATETIME2 NOT NULL;
ALTER TABLE ProjectTaskHistory
ALTER COLUMN [ValidFrom] DATETIME2 NOT NULL;
ALTER TABLE ProjectTaskHistory
ALTER COLUMN [ValidTo] DATETIME2 NOT NULL;
ALTER TABLE ProjectTaskCurrent ADD PERIOD
FOR SYSTEM_TIME([ValidFrom], [ValidTo]);
ALTER TABLE ProjectTaskCurrent SET (
SYSTEM_VERSIONING = ON (
HISTORY_TABLE = dbo.ProjectTaskHistory,
DATA_CONSISTENCY_CHECK = ON
)
);
Comentários
- Referenciar colunas existentes na
PERIOD
definição mudagenerated_always_type
implicitamente paraAS_ROW_START
eAS_ROW_END
para essas colunas. - Adicionar
PERIOD
executa um marcar de consistência de dados na tabela atual para garantir que os valores existentes para colunas de período sejam válidos - É altamente recomendável definir
SYSTEM_VERSIONING
comDATA_CONSISTENCY_CHECK = ON
para impor verificações de consistência de dados em dados existentes. - Se as colunas ocultas forem preferenciais, use o comando
ALTER TABLE [tableName] ALTER COLUMN [columnName] ADD HIDDEN;
.
Próximas etapas
- Tabelas temporais
- Introdução com tabelas temporais com controle de versão do sistema
- Gerenciar a retenção de dados históricos em tabelas temporais com versão do sistema
- Tabelas temporais com controle da versão do sistema com tabelas com otimização de memória
- CREATE TABLE (Transact-SQL)
- Modificando dados em uma tabela temporal com versão do sistema
- Consultar dados em uma tabela temporal com versão do sistema
- Alterando o esquema de uma tabela temporal com controle de versão do sistema
- Parar o controle de versão do sistema em uma tabela temporal com versão do sistema