BASLE BERN BRUGG DÜSSELDORF FRANKFURT A.M. FREIBURG I.BR. GENEVA HAMBURG COPENHAGEN LAUSANNE MUNICH STUTTGART VIENNA ZURICH SQL Server 2016 Temporal Tables Willfried Färber – BS [email protected]
Jan 23, 2018
BASLE BERN BRUGG DÜSSELDORF FRANKFURT A.M. FREIBURG I.BR. GENEVA
HAMBURG COPENHAGEN LAUSANNE MUNICH STUTTGART VIENNA ZURICH
SQL Server 2016 Temporal Tables
Willfried Färber – [email protected]
Agenda
1. Overview of SQL Server 2016 temporal tables
2. Data Definition for temporal tables
3. Data Manipulation with temporal tables
4. Usage Scenarios
Why – History Tables
• Auditing all data changes and performing data
forensics when necessary
• Reconstructing state of the data as of any time in
the past
• Calculating trends over time – Anomaly Detection
• Maintaining a slowly changing dimension for
decision support applications
• Recovering from accidental data changes and
application errors
What is a Temporal Table?
• A temporal table is a table for which a PERIOD definition exists and which
contains system columns with a datatype of datetime2 into which the period
of validity is recorded by the system, and which has an associated history
table into which the system records all prior versions of each record with
their period of validity.
• With a temporal table, the value of each record at any point in time can be
determined, rather than just the current value of each record. A temporal
table is also referred to as a system-versioned table.
Temporal Tables
Automatically keeps track of changed data
• Along with period of validity
• Available in all editions of SQL Server (from the Express!)
• Available in SQL Azure
• SQL ANSI 2011 compliant
• Provide native support for “as-of-time” queries
• Transparent to existing applications (if needed)
• Integrated with existing features (eg: Partitioning, Hekaton)
• Integrated with new features (eg: Stretch Database)
Insert, Update, Delete
New clauses – Data Definition
CREATE TABLE Department ( DeptID int NOT NULL PRIMARY KEY CLUSTERED , DeptName varchar(50) NOT NULL , ManagerID INT NULL , ParentDeptID int NULL , SysStartTime datetime2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL , SysEndTime datetime2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL , PERIOD FOR SYSTEM_TIME (SysStartTime, SysEndTime)
) WITH ( SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.DepartmentHistory) ) ;
GENERATED ALWAYS AS ROW START
GENERATED ALWAYS AS ROW END
PERIOD FOR SYSTEM_TIME
SYSTEM_VERSIONING = ON
BEGIN TRANSACTION
-- Add required period columns and designationALTER TABLE dbo.Person ADD
DateTimeStart DATETIME2(0) GENERATED ALWAYS AS ROW START NOT NULLCONSTRAINT DFT_person_datetimeStart DEFAULT('19000101 00:00:00'),
DateTimeEnd DATETIME2(0) GENERATED ALWAYS AS ROW END NOT NULLCONSTRAINT DFT_person_datetimeEnd DEFAULT('99991231 23:59:59'),
PERIOD FOR SYSTEM_TIME (DateTimeStart, DateTimeEnd);
-- Remove temporary DEFAULT constraintsALTER TABLE dbo.Person
DROP CONSTRAINT DFT_person_datetimeStart, DFT_person_datetimeEnd;
-- Turn system versioning onALTER TABLE dbo.Person
SET ( SYSTEM_VERSIONING = ON ( HISTORY_TABLE = dbo.PersonHistory ) );
COMMIT TRANSACTION;
System generated temporal table
SQL Server 2016 Temporal Tables9 30-Oct-17
Creating through SSMS
Querying temporal data
FOR predicate
SQL Server 2016 Temporal Tables11 30-Oct-17
Expression Qualifying Rows
AS OF <date_time> SysStartTime < = date_time AND SysEndTime >
date_time
FROM <start_date_time>
TO <end_date_time>
SysStartTime < end_date_time AND SysEndTime >
start_date_time
BETWEEN
<start_date_time> AND
<end_date_time>
SysStartTime < = end_date_time AND SysEndTime >
start_date_time
CONTAINED IN
(<start_date_time>,
<end_date_time>)
SysStartTime > = start_date_time AND SysEndTime < =
end_date_time
ALL all rows
New clauses – AS OF
DECLARE @datetime AS DATETIME2 = '20161108 20:00:00'
SELECT *FROM dbo.Person FOR SYSTEM_TIME AS OF @datetimeORDER BY DateTimeStart ASC,
DateTimeEnd ASC
Clauses SYSTEM_TIME allow to realize temporal queries transparently for user and applications.
FOR SYSTEM_TIME AS OF @datetime
Reference: http://sqlmag.com/sql-server/first-look-system-versioned-temporal-tables-part-2-querying-data-and-optimization-conside (Itzik Ben Gan)
sysEnd > @datetime
sysStart <= @datetime
New clauses – AS OF
Returns a table with a rows containing
the values that were actual (current) at
the specified point in time in the past.
FOR SYSTEM_TIME FROM @Start TO @End
Reference: http://sqlmag.com/sql-server/first-look-system-versioned-temporal-tables-part-2-querying-data-and-optimization-conside (Itzik Ben Gan)
sysStart < @End
sysEnd > @Start
New clauses – AS OF
Returns a table with the values for all row
versions that were active within the
specified time range, regardless of
whether they started being active before
the <start_date_time> parameter value for
the FROM argument or ceased being
active after the <end_date_time>
parameter value for the TO argument.
FOR SYSTEM_TIME BETWEEN @Start AND @End
Reference: http://sqlmag.com/sql-server/first-look-system-versioned-temporal-tables-part-2-querying-data-and-optimization-conside (Itzik Ben Gan)
sysStart <= @End
sysEnd > @Start
New clauses – AS OF
Same as above in the FOR SYSTEM_TIME
FROM <start_date_time> TO
<end_date_time> description, except the
table of rows returned includes rows that
became active on the upper boundary
defined by the <end_date_time> endpoint.
FOR SYSTEM_TIME CONTAINED IN (@Start,@End)
Reference: http://sqlmag.com/sql-server/first-look-system-versioned-temporal-tables-part-2-querying-data-and-optimization-conside (Itzik Ben Gan)
sysStart >= @Start
sysEnd <= @End
New clauses – AS OF
Returns a table with the values for all row
versions that were opened and closed within
the specified time range defined by the two
datetime values for the CONTAINED IN
argument.
Considerations for resource use
• A temporal table must have a primary key defined in order to correlate records between the
current table and the history table, and the history table cannot have a primary key defined.
• The SYSTEM_TIME period columns used to record the SysStartTime and SysEndTime values
must be defined with a datatype of datetime2.
• If the name of a history table is specified during history table creation, you must specify the
schema and table name.
• By default, the history table is PAGE compressed.
• If current table is partitioned, the history table is created on default file group because partitioning
configuration is not replicated automatically from the current table to the history table.
• Temporal and history tables cannot be FILETABLE and can contain columns of any
supported datatype other than FILESTREAM since FILETABLE and FILESTREAM allow data
manipulation outside of SQL Server and thus system versioning cannot be guaranteed.
More work, but much better …
SQL Server 2016 Temporal Tables18 30-Oct-17
Define the history table by your self
• Define a separate filegroup
• Use a special schema – iE. History
• Maybe use Column Store Index
• Maybe use Partitions
• Create Clustered Index on the file table
CREATE CLUSTERED INDEX uidx_<tablename>_hist ON <tablename>(ValidTo ASC, ValidFrom ASC, EmployeeID ASC)
ON [History];
Limitations…
• TRUNCATE TABLE is not supported while SYSTEM_VERSIONING is ON
• Direct modification of the data in a history table is not permitted.
• ON DELETE CASCADE and ON UPDATE CASCADE are not permitted on the current table. In
other words, when temporal table is referencing table in the foreign key relationship
(corresponding to parent_object_id in sys.foreign_keys) CASCADE options are not allowed. To
work around this limitation, use application logic or after triggers to maintain consistency on delete
in primary key table (corresponding to referenced_object_id in sys.foreign_keys). If primary key
table is temporal and referencing table is non-temporal, there’s no such limitation.
• INSTEAD OF triggers are not permitted on either the current or the history table and AFTER
triggers are permitted only on the current table.
• Regular queries only affect data in the current table. To query data in the history table, you must
use temporal queries.
Security for temporal tables
SQL Server 2016 Temporal Tables20 30-Oct-17
• Creating a temporal table requires CONTROL rights
• DBOwner has Control rights in the database
• When SYSTEM_VERSIONING is ON users cannot alter history data regardless of
their actual permissions on current or the history table. This includes both data and
schema modifications
• Querying history data requires SELECT permission on the history table
• Merely because a user has SELECT permission on the current table does not
mean that they have SELECT permission on the history table
https://msdn.microsoft.com/en-us/library/mt604469.aspx
Willfried Färber
Principal Consultant
Tel. +41 58 459 50 11
30.10.2017 SQL Server 2016 Temporal Tables21
Source code for the demos
SQL Server 2016 Temporal Tables22 30.10.2017