SQL Server 2014新功能 -- 內存中OLTP(In-Memory OLTP)

SQL Server 2014新功能 -- 內存中OLTP(In-Memory OLTP


概述


內存中OLTP(項目“Hekaton”)是一個全新的、完全集成到SQL Server的數據庫引擎組件。 對OLTP工作負載訪問中在內存中的數據進行了優化。內存中OLTP能夠幫助OLTP工作負載實現顯著的性能改善,並減少處理時間。表能被視爲“內存優化”,提升內存中的OLTP功能。內存優化表是完全可事務的、並可以使用Transact-SQL進行訪問。Transact-SQL存儲過程可以編譯成爲機器碼,從而進一步地提高內存優化表的性能。該引擎是專爲高併發而設計的,並且阻塞是最小的。

 

術語


基於磁盤的表:

傳統的表存儲方式,具有以下主要屬性:

· 映射到一個文件組,並且該文件組包含一個或多個文件。

· 每個文件劃分爲 8 個頁區,每頁的大小爲 8K 字節。

· 可跨多個表共享一個區,但分配的頁和表或索引之間存在一對一映射。 換言之,一個頁面不能有來自兩個或更多表或索引的行。

· 根據需要將數據移到內存(緩衝池)中,並且修改後的或新建的頁面將以異步方式寫入到主要生成隨機 IO 的磁盤。

 

內存優化表:

內存優化表的存儲具有以下主要屬性:

· 所有內存優化表都映射到內存優化的文件組。 使用文件流文件組生成此文件組。

· 不存在任何頁面,並且數據以行的形式保留。

· 對內存優化表進行的所有更改都通過追加到活動文件進行存儲。 對文件進行的讀取和寫入操作是有順序的。

· 按照先刪除再插入的方式實現更新。 不會立即從存儲中移除已刪除的行。 依據內存優化表的持久性中所述的策略,已刪除的行由稱作 MERGE 的後臺進程移除。

· 與基於磁盤的表不同,不對內存優化表的存儲進行壓縮。 在將壓縮的(ROW 或 PAGE)基於磁盤的表遷移到內存優化表時,您將需要考慮大小的更改。

· 內存優化表可以是持久的或非持久的。 您只需爲持久性內存優化表配置存儲。

 

跨容器的事務:

是指同時參考內存優化表和基於磁盤的表的事務。

 

互操作性:

是指引用內存優化表的解釋型的Transact-SQL。

 

可編譯的Transact-SQL:

即傳統的解釋性Transact-SQL。當使用互操作時,內存優化表將會訪問所有的Transact- SQL區域,但您不應該指望取得使用本地編譯存儲過程相同的性能。當運行即席查詢時,互操作是合適的選擇,或在應用程序遷移到內存中的OLTP之前使用。這種使用是最佳性能的關鍵程序遷移過程中的一個步驟。當您需要同時訪問內存優化表和基於磁盤的表時,也可以使用可編譯的Transact-SQL 。

 

Transact-SQL使用互操作訪問內存優化表時,不支持的功能僅有以下幾種:

· TRUNCATE TABLE;

· MERGE(內存優化表的目標);

· 動態和基於鍵值集的遊標(這些都是自動降級到靜態遊標);

· 跨數據庫中的查詢;

· 跨數據庫中的事務;

· 鏈接服務器;

· 鎖定提示:TABLOCK、XLOCK、PAGLOCK等(NOLOCK支持);

· 隔離級別的提示READUNCOMMITTED、READCOMMITTED READCOMMITTEDLOCK;

· 內存優化的表類型和表中不只是由CTP1支持的變量。

 

本地編譯的存儲過程:

是指一種對象類型,這種類型被內存駐留OLTP所支持;內存駐留OLTP被編譯爲機器代碼,並有可能進一步提高性能,甚至比只使用內存優化表更加優化。另一種替代方案是採用基於解釋型的Transact-SQL存儲過程,這是SQL Server中常用的、採用基礎的編譯的存儲過程只能引用內存優化表。

 

包含內存中OLTP組件的SQL Server引擎


雖然內存駐留OLTP 與SQL Server關係型引擎集成,並能通過相同的接口訪問,但是其內部的行爲和性能卻大相徑庭。

image

 

無論調用本地編譯的存儲過程或者Transact-SQL,客戶端應用程序採用與內存優化表或基於磁盤的表同樣的方式連接到TDS處理器。您可以看到解釋型的Transact-SQL能通過互操作能力訪問內存優化表,但本地編譯的存儲過程只能訪問內存優化表。

 

使用內存中OLTP


內存中OLTP引擎從2013年6月CTP版本開始,已經成爲SQL Server 2014的一部分。內存中OLTP SQL Server的安裝是SQL Server安裝程序的一部分。內存中OLTP組件只能被安裝在一個SQL Server 2014 64位版本中,而不與32位版本兼容。

 

準備:創建示例數據庫

CREATE DATABASE imoltp
GO

 

第一步:設置數據庫支持內存中OLTP

包含內存優化表的任何數據庫至少需要有一個MEMORY_OPTIMIZED_DATA文件組。這些文件組用於存儲數據和增量文件,這些文件被SQL Server用來恢復內存優化表。雖然創建MEMORY_OPTIMIZED_DATA文件組與創建常規FILESTREAM文件組的語法幾乎是相同的,但是還是必須要指定CONTAINS MEMORY_OPTIMIZED_DATA這一選項。

 

下面通過兩種方式來添加MEMORY_OPTIMIZED_DATA文件組和存放FILESTREAM文件的容器。

 

使用T-SQL實現:

ALTER DATABASE imoltp ADD FILEGROUP imoltp_mod CONTAINS MEMORY_OPTIMIZED_DATA
ALTER DATABASE imoltp ADD FILE (name='imoltp_mod1', filename='E:\SQL-DATA\imoltp_mod1') TO FILEGROUP imoltp_mod
GO

 

使用SSMS實現:


1. 在Object Explorer中, 展開數據庫節點, 右鍵點擊數據庫,單擊屬性。  
image

 

2. 添加一個新的內存優化數據的文件組,點擊文件組頁面。在MEMORY OPTIMIZED DATA選項下,單擊添加文件組並設置文件組的各項值。  
image

 

3. 在文件組中添加文件,點擊general 頁面。 在Database files下,點擊添加並且輸入文件的各項值。File type 設置爲FILESTREAM Data。  
image

 

第二步:創建內存優化表

創建優化內存表的語法與創建基於磁盤的表的語法幾乎相同,只有一些限制以及需要的擴展。指定表是內存優化表是用MEMORY_OPTIMIZED= ON語句實現的。內存優化表只可以有以下這些可支持的數據類型的列:

· 字節;

· 所有整數類型:tinyint、smallint、int、bigint;

· 所有money類型:money、smallmoney;

· 所有浮點類型:float、real;

· 所有日期/時間類型:datetime、smalldatetime、datetime2、date、time;

· 數字和浮點數類型;

· 所有非LOB字符類型:char(n)、varchar(n)、nchar(n)、nvarchar(n)、sysname;

· 非LOB二進制類型:binary(n)、varbinary(n);

· 獨特的識別符。

 

請注意的是LOB數據類型是不可用的;不能有XML類型、CLR、或者max數據類型的列,並且所有行的長度都限制在8060個字節之內,而且沒有行外數據。事實上,8060字節的限制是在表創建的時候執行的,所以不像基於磁盤的表,內存優化表不能創建兩個varchar(5000)的列。

 

內存優化表可以通過兩種DURABILITY值定義:SCHEMA_AND_DATA或SCHEMA_ONLY,前者是默認值。內存優化表由DURABILITY=SCHEMA_ONLY定義,這意味着表中數據的變化沒有被記錄下來,並且表中的數據並沒有保存在磁盤上。但是,架構會被作爲數據庫元數據的一部分保存下來,所以在一個SQL Server重啓的過程中恢復數據庫之後,這樣的空表是可用的。

 

如前所述,內存優化表必須至少有一個索引,但這一要求能通過索引自動創建來滿足,從而支持主鍵約束。除了那些用schema_only選項所創建的表以外的其他表都必須有一個聲明的主鍵。至少有一個索引必須聲明支持一個主鍵約束。下面的示例顯示了一個主鍵索引創建成爲一個分區索引,其中的統計指標也必須被指定。

 

當創建內存優化表時,除已列的對數據類型的限制之外,只有少數的其他限制:

· 沒有DML觸發器;

· 沒有FOREIGN KEY或CHECK約束;

· 沒有IDENTITY列;

· 除了主鍵沒有唯一索引;

· 最多8個索引,包括支持主鍵的索引。

 

此外,一旦一個表被創建後,架構是不可改變的。您將需要刪除並重新創建表,而不是使用ALTER TABLE。此外,並沒有具體的索引DDL命令(比如創建索引、修改索引、刪除索引)。索引總是作爲表創建的一部分而創建。

 

目前我們有兩張表,‘ShoppingCart’和‘UserSession’。‘ShoppingCart’是一個持久化的表(默認值),這意味着表中的內容是存儲在磁盤上的,不會因爲服務器崩潰而丟失。‘UserSession’是一個非持久化的表(DURABILITY=SCHEMA_ONLY),這意味着表中內容僅存儲在內存中,服務器重啓即會丟失。

 

注:SQL 2014 內存優化的表支持非聚集哈希索引(hash index)和非聚集索引(rang index)。hash索引的Bucket_cout建議值是表中能找到的唯一索引鍵值個數的4到8倍。

 

下面通過兩種方式來創建內存優化表。

 

使用T-SQL實現:

USE imoltp
GO
-- durable table (持久化的表)
CREATE TABLE dbo.ShoppingCart (
ShoppingCartId int not null primary key nonclustered hash with
(bucket_count=2000000),
UserId int not null index ix_UserId nonclustered hash with (bucket_count=1000000),
CreatedDate datetime2 not null,
TotalPrice money
)
WITH (MEMORY_OPTIMIZED=ON)
GO
-- non-durable table (非持久化的表)
CREATE TABLE dbo.UserSession (
SessionId int not null primary key nonclustered hash with (bucket_count=400000),
UserId int not null,
CreatedDate datetime2 not null,
ShoppingCartId int,
index ix_UserId nonclustered hash (UserId) with (bucket_count=400000)
)
WITH(MEMORY_OPTIMIZED=ON, DURABILITY=SCHEMA_ONLY)
GO

 

使用SSMS實現:

1. 在Object Explorer,右鍵單擊您數據庫的Tables節點,點擊new,然後點擊Memory Optimized Table。然後可以看到創建內存優化表的模板。  
image

 

2. 替換模板中的參數,在query菜單中點擊Specify Values for Template Parameters。快捷鍵是Ctrl-Shift-M。  
image

 

3. 執行完畢後,確認表已創建。  
image

 

第三步:加載數據

可以通過多種方式把數據加載到表中,包括 INSERT .. SELECT from一個已經存在的存儲在磁盤上的表和BCP。

 

-- insert a few rows
INSERT dbo.UserSession VALUES (1,342,GETUTCDATE(),4)
INSERT dbo.UserSession VALUES (2,65,GETUTCDATE(),NULL)
INSERT dbo.UserSession VALUES (3,8798,GETUTCDATE(),1)
INSERT dbo.UserSession VALUES (4,80,GETUTCDATE(),NULL)
INSERT dbo.UserSession VALUES (5,4321,GETUTCDATE(),NULL)
INSERT dbo.UserSession VALUES (6,8578,GETUTCDATE(),NULL)
INSERT dbo.ShoppingCart VALUES (1,8798,GETUTCDATE(),NULL)
INSERT dbo.ShoppingCart VALUES (2,23,GETUTCDATE(),45.4)
INSERT dbo.ShoppingCart VALUES (3,80,GETUTCDATE(),NULL)
INSERT dbo.ShoppingCart VALUES (4,342,GETUTCDATE(),65.4)
GO
-- verify table contents
SELECT * FROM dbo.UserSession
SELECT * FROM dbo.ShoppingCart
GO

 

第四步:更新統計信息

內存優化的表不支持auto_update_statistics,因此統計信息需要手動進行更新。您可以使用UPDATE STATISTICS來更新單個表的統計信息或者sp_updatestats來更新數據庫中的所有表的統計信息。

 

-- update statistics on memory optimized tables
UPDATE STATISTICS dbo.UserSession WITH FULLSCAN, NORECOMPUTE
UPDATE STATISTICS dbo.ShoppingCart WITH FULLSCAN, NORECOMPUTE
GO

 

第五步:執行查詢

優化內存表可以以兩種不同的方式訪問:要麼通過可編譯的Transact-SQL互操作,或通過本地編譯的存儲過程。

 

現在您已經做好了執行查詢的準備。因爲查詢需要訪問內存優化的表,他們將會受益於不加鎖的數據結構,從而提高了數據訪問的效率。以下是一些例子:

 

-- in an explicit transaction, assign a cart to a session and update the total price.
-- note that the isolation level hint is required for memory-optimized tables with
-- SELECT/UPDATE/DELETEstatements in explicit transactions
BEGIN TRAN
UPDATE dbo.UserSession WITH (SNAPSHOT) SET ShoppingCartId=3 WHERE SessionId=4
UPDATE dbo.ShoppingCart WITH (SNAPSHOT) SET TotalPrice=65.84 WHERE ShoppingCartId=3
COMMIT
GO
-- verify table contents
SELECT * FROM dbo.UserSession u JOIN dbo.ShoppingCart s on u.ShoppingCartId=s.ShoppingCartId
WHERE u.SessionId=4
GO

 

image

 

第六步:創建本地編譯的存儲過程

爲了進一步優化內存優化表的訪問以及優化您的業務邏輯的執行,您可以選擇創建本地編譯的存儲過程。這些存儲過程是使用Transact-SQL創建的,但並不支持完整的Transaction-SQL環境。具體細節可參考聯機叢書。

 

以下是一個訪問之前我們創建的表的本地編譯的存儲過程的例子。

 

-- natively compiled stored procedure for assigning a shopping cart to a session
CREATE PROCEDURE dbo.usp_AssignCart @SessionId int
WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER
AS
BEGIN ATOMIC
WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english')
DECLARE @UserId int,
@ShoppingCartId int
SELECT @UserId=UserId, @ShoppingCartId=ShoppingCartId
FROM dbo.UserSession WHERE SessionId=@SessionId
IF @UserId IS NULL
THROW 51000, 'The session or shopping cart does not exist.', 1
UPDATE dbo.UserSession SET ShoppingCartId=@ShoppingCartId WHERE SessionId=@SessionId
END
GO
EXEC usp_AssignCart 1
GO

 

下面的存儲過程通過向內存優化表中插入大量數據行來測試本地編譯的存儲過程的性能。該腳本插入了1,000,000行數據。

 

需要注意的是如果寫事物日誌文件變成應用的性能瓶頸,SQL Server允許您採用非持久化的表(DURABILITY=SCHEMA_ONLY)來完全除去寫事務日誌。

 

-- natively compiled stored procedure for inserting a large number of rows
-- this demonstrates the performance of native procs
CREATE PROCEDURE dbo.usp_InsertSampleCarts @StartId int, @InsertCount int
WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER
AS
BEGIN ATOMIC
WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT, LANGUAGE = N'us_english')
DECLARE @ShoppingCartId int = @StartId
WHILE @ShoppingCartId < @StartId + @InsertCount
BEGIN
INSERT INTO dbo.ShoppingCart VALUES
(@ShoppingCartId, 1, '2013-01-01T00:00:00', NULL)
SET @ShoppingCartId += 1
END
END
GO
-- insert 1,000,000 rows
DECLARE @StartId int = (SELECT MAX(ShoppingCartId)+1 FROM dbo.ShoppingCart)
EXEC usp_InsertSampleCarts @StartId, 1000000
GO
-- verify the rows have been inserted
SELECT COUNT(*) FROM dbo.ShoppingCart
GO

 

使用SSMS創建本地編譯的存儲過程:

1. 在 Object Explorer中,右鍵單擊您的數據庫中的Stored Procedures 節點,點擊New,然後點擊 Natively Compiled Stored Procedure。創建本地編譯的存儲過程的模板將會顯示在界面上。  
image

 

2. 替換模板中的參數,點擊Query 菜單下的 Specify Values for Template Parameters。快捷鍵是Ctrl-Shift-M。  
image

 

SQL Server功能支持


很多SQL Server功能所支持的內存駐留OLTP和數據庫包含內存優化表。例如,AlwaysOn的組件,日誌傳送和數據庫備份和恢復被完全支持。但是,數據庫鏡像和複製不被支持。您可以使用SQL Server Management Studio以支持內存優化表和SSIS工作。

 

對於支持和不支持的功能的完整列表,請參閱到SQL Server 內存駐留OLTP文檔。

 

總結

 

SQL Server內存駐留OLTP提供了可創造和運行內存優化的極其高效的管理,實現了對OLTP工作負載的性能優化。真正實現了多版本的積極併發控制,且無需在訪問過程中鎖定。所有內存駐留OLTP內存優化表必須至少擁有一個索引,然後所有對這類表的訪問都需要通過這些索引進行。除少量限制情況下外,內存駐留OLTP內存優化表可以作爲基於磁盤表中的相同引用的事務。本地編譯的存儲過程以最快的方式來使用您的內存優化表和性能業務邏輯計算。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章