Speicheroptimierte Tabellenvariablen
Zusätzlich zu speicheroptimierten Tabellen (für den effizienten Datenzugriff) und systemintern kompilierten gespeicherten Prozeduren (für effiziente Abfrageverarbeitung und Ausführung von Geschäftslogik) wird mit In-Memory OLTP eine dritte Objektart eingeführt: speicheroptimierte Tabellentypen. Eine Tabellenvariable, die mithilfe eines speicheroptimierten Tabellentyps erstellt wird, ist eine speicheroptimierte Tabellenvariable.
Speicheroptimierte Tabellenvariablen bieten im Vergleich zu datenträgerbasierten Tabellenvariablen die folgenden Vorteile:
Die Variablen werden nur im Arbeitsspeicher gespeichert. Die Datenzugriffe sind effizienter, da für speicheroptimierte Tabellentypen derselbe speicheroptimierte Algorithmus und dieselben Datenstrukturen verwendet werden wie für speicheroptimierte Tabellen, insbesondere wenn die Variablen in systemintern kompilierten gespeicherten Prozeduren verwendet werden.
Bei speicheroptimierten Tabellenvariablen findet keine tempdb-Nutzung statt. Tabellenvariablen werden nicht in tempdb gespeichert und verwenden keine Ressourcen in tempdb.
Typische Verwendungsszenarien für speicheroptimierte Tabellenvariablen sind:
Speichern von Zwischenergebnissen und Erstellen von einzelnen Resultsets, die auf mehreren Abfragen basieren, in systemintern kompilierten gespeicherten Prozeduren.
Übergeben von Tabellenwertparametern an systemintern kompilierte gespeicherte Prozeduren und an interpretierte gespeicherte Prozeduren.
Ersetzen datenträgerbasierter Tabellenvariablen und in einigen Fällen von lokalen #temp-Tabellen einer gespeicherten Prozedur. Dies ist besonders dann nützlich, wenn im System viele tempdb-Konflikte auftreten.
Tabellenvariablen können zum Simulieren von Cursorn in systemintern kompilierten gespeicherten Prozeduren verwendet werden, um Einschränkungen der Oberfläche in systemintern kompilierten gespeicherten Prozeduren zu umgehen.
Wie speicheroptimierte Tabellen generiert SQL Server eine DLL für jeden speicheroptimierten Tabellentyp. (Die Kompilierung wird aufgerufen, wenn der speicheroptimierte Tabellentyp erstellt wird, und nicht, wenn sie zum Erstellen speicheroptimierter Tabellenvariablen verwendet wird.) Diese DLL enthält die Funktionen für den Zugriff auf Indizes und das Abrufen von Daten aus den Tabellenvariablen. Wenn eine speicheroptimierte Tabellenvariable basierend auf dem Tabellentyp deklariert wird, wird in der Benutzersitzung eine Instanz der Tabelle und der Indexstrukturen entsprechend dem Tabellentyp erstellt. Die Tabellenvariable kann anschließend auf dieselbe Weise wie datenträgerbasierte Tabellenvariablen verwendet werden. Sie können Zeilen in der Tabellenvariablen einfügen, aktualisieren und löschen, und Sie können die Variablen in Transact-SQL-Abfragen verwenden. Sie können die Variablen auch als Tabellenwertparameter (TVPs) an systemintern kompilierte und interpretierte gespeicherte Prozeduren übergeben.
Das folgende Beispiel zeigt einen speicheroptimierten Tabellentyp aus dem AdventureWorks-basierten In-Memory OLTP-Beispiel (SQL Server 2014 In-Memory OLTP-Beispiel).
CREATE TYPE Sales.SalesOrderDetailType_inmem
AS TABLE
(
OrderQty smallint NOT NULL,
ProductID int NOT NULL,
SpecialOfferID int NOT NULL
INDEX IX_SpecialOfferID NONCLUSTERED,
LocalID int NOT NULL,
INDEX IX_ProductID HASH (ProductID)
WITH ( BUCKET_COUNT = 8 )
)
WITH ( MEMORY_OPTIMIZED = ON );
Das Beispiel zeigt, dass die Syntax von speicheroptimierten Tabellentypen der von datenträgerbasierten Tabellentypen ähnelt, mit folgenden Ausnahmen:
MEMORY_OPTIMIZED=ON
gibt an, dass der Tabellentyp speicheroptimiert ist.Der Typ muss mindestens einen Index aufweisen. Wie bei speicheroptimierten Tabellen können Sie nicht gruppierte und Hashindizes verwenden.
Für einen Hashindex sollte die Bucketanzahl etwa einmal bis zweimal so groß sein wie die Anzahl der erwarteten eindeutigen Indexschlüssel. Weitere Informationen finden Sie unter Determining the Correct Bucket Count for Hash Indexes.
Der Datentypbeschränkungen und die Einschränkungen für speicheroptimierte Tabellen gelten auch für speicheroptimierte Tabellentypen. In SQL Server 2014 werden beispielsweise Standardeinschränkungen unterstützt, check-Einschränkungen jedoch nicht.
Speicheroptimierte Tabellenvariablen verhalten sich in folgenden Fällen wie speicheroptimierte Tabellen:
Sie unterstützen keine parallelen Pläne.
Sie müssen in den Arbeitsspeicher passen und nutzen keine Datenträgerressourcen.
Datenträgerbasierte Tabellenvariablen werden in tempdb gespeichert. Speicheroptimierte Tabellenvariablen werden in der Benutzerdatenbank gespeichert. (Sie belegen aber keinen Speicherplatz und werden nicht wiederhergestellt.)
Eine speicheroptimierte Tabellenvariable kann nicht mithilfe von Inlinesyntax erstellt werden. Im Gegensatz zu datenträgerbasierten Tabellenvariablen müssen Sie zuerst einen Typ erstellen.
Tabellenwertparameter
Im folgenden Beispielskript wird die Deklaration einer Tabellenvariablen als speicheroptimierter Tabellentyp Sales.SalesOrderDetailType_inmem
, das Einfügen von drei Zeilen in die Variable und das Übergeben der Variablen als TVP an Sales.usp_InsertSalesOrder_inmem
gezeigt.
DECLARE @od Sales.SalesOrderDetailType_inmem,
@SalesOrderID uniqueidentifier,
@DueDate datetime2 = SYSDATETIME()
INSERT @od (LocalID, ProductID, OrderQty, SpecialOfferID) VALUES
(1, 888, 2, 1),
(2, 450, 13, 1),
(3, 841, 1, 1)
EXEC Sales.usp_InsertSalesOrder_inmem
@SalesOrderID = @SalesOrderID,
@DueDate = @DueDate,
@OnlineOrderFlag = 1,
@SalesOrderDetails = @od
Speicheroptimierte Tabellentypen können als Typ für Tabellenwertparameter (TVPs) von gespeicherten Prozeduren verwendet werden. Clients können genauso darauf verweisen wie auf datenträgerbasierte Tabellentypen und TVPs. Daher funktioniert der Aufruf gespeicherter Prozeduren mit speicheroptimierten TVPs und systemintern kompilierter gespeicherter Prozeduren genauso wie der Aufruf interpretierter gespeicherter Prozeduren mit datenträgerbasierten TVPs.
Ersatz für #temp-Tabellen
Im folgenden Beispiel werden speicheroptimierte Tabellentypen und Tabellenvariablen als Ersatz für lokale #temp-Tabellen einer gespeicherten Prozedur verwendet.
-- Using SQL procedure and temp table
CREATE TABLE #tempTable (c INT NOT NULL PRIMARY KEY NONCLUSTERED)
CREATE PROCEDURE sqlProc
AS
BEGIN
TRUNCATE TABLE #tempTable
INSERT #tempTable VALUES (1)
INSERT #tempTable VALUES (2)
INSERT #tempTable VALUES (3)
SELECT * FROM #tempTable
END
GO
-- Using natively compiled stored procedure and table variable
CREATE TYPE TT AS TABLE (c INT NOT NULL PRIMARY KEY NONCLUSTERED)
GO
CREATE PROCEDURE NCSPProc
WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER
AS
BEGIN ATOMIC WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english')
DECLARE @tableVariable TT
INSERT @tableVariable VALUES (1)
INSERT @tableVariable VALUES (2)
INSERT @tableVariable VALUES (3)
SELECT c FROM @tableVariable
END
GO
Erstellen eines einzelnen Resultsets
Im folgenden Beispiel wird gezeigt, wie Zwischenergebnisse gespeichert und einzelne Resultsets basierend auf mehreren Abfragen in systemintern kompilierten gespeicherten Prozeduren erstellt werden. Im Beispiel wird die Vereinigung SELECT c1 FROM dbo.t1 UNION SELECT c1 FROM dbo.t2
berechnet.
CREATE DATABASE hk
GO
ALTER DATABASE hk ADD FILEGROUP hk_mod CONTAINS MEMORY_OPTIMIZED_DATA
ALTER DATABASE hk ADD FILE( NAME = 'hk_mod' , FILENAME = 'c:\data\hk_mod') TO FILEGROUP hk_mod;
USE hk
GO
CREATE TYPE tab1 AS TABLE (c1 INT NOT NULL, INDEX idx NONCLUSTERED(c1)) WITH (MEMORY_OPTIMIZED = ON)
CREATE TABLE dbo.t1 (c1 INT NOT NULL, INDEX idx NONCLUSTERED(c1)) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY)
CREATE TABLE dbo.t2 (c1 INT NOT NULL, INDEX idx NONCLUSTERED(c1)) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY)
INSERT INTO dbo.t1 VALUES (1), (2)
INSERT INTO dbo.t2 VALUES (3), (4)
GO
CREATE PROCEDURE dbo.p1
WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER
AS
BEGIN ATOMIC WITH ( TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english' )
DECLARE @t dbo.tab1
INSERT @t (c1)
SELECT c1 FROM dbo.t1;
INSERT @t (c1)
SELECT c1 FROM dbo.t2;
SELECT c1 FROM @t;
END
GO
EXEC dbo.p1
GO
Arbeitsspeichernutzung für Tabellenvariablen
Die Arbeitsspeichernutzung für Tabellenvariablen ist mit Ausnahme von nicht gruppierten Indizes mit der Nutzung speicheroptimierter Tabellen vergleichbar. Wenn Sie viele Zeilen in speicheroptimierte Tabellenvariablen mit nicht gruppierten Indizes einfügen und die Indexschlüssel groß sind, beanspruchen diese Tabellenvariablen eine unverhältnismäßig große Speichermenge. Nicht gruppierte Indizes für große Tabellenvariablen erfordern proportional mehr Arbeitsspeicher, als ein nicht gruppierter Index für dieselbe Anzahl von Zeilen, die in eine Tabelle eingefügt wurden, benötigen würde (mehr Speicherplatz in Indexseiten).
Arbeitsspeicher für Tabellenvariablen wird aus dem Ressourcenpool der für die Datenbank zuständigen Ressourcenkontrolle entnommen.
Im Gegensatz zu speicheroptimierten Tabellen wird der von Tabellenvariablen genutzte Arbeitsspeicher (einschließlich gelöschter Zeilen) freigegeben, wenn die Tabellenvariable den Gültigkeitsbereich verlässt.
Arbeitsspeicher wird als Teil des einzelnen PGPOOL-Arbeitsspeicherconsumers der Datenbank behandelt.