將一個基於磁盤的表遷移到SQL Server中的一個內存優化的表
本文是微軟的譯文,對應的原文是:https://www.red-gate.com/simple-talk/sql/database-administration/migrating-disk-based-table-memory-optimized-table-sql-server/
以前稱為Hekaton的特性,現在是內存中的OLTP,可以提供非常有用的性能提升,您可以仔細地選擇表來進行內存優化。如何將現有表轉換為內存優化的表呢?這個過程不是很簡單,但是內存中的OLTP表所帶來的好處是值得您付出努力的。Alex Grinberg帶著你的基本知識。
內存中的OLTP,也稱為Hekaton,可以顯著提高OLTP(聯機事務處理)數據庫應用程序的性能。它提高了吞吐量,減少了事務處理的延遲,並且可以幫助改善數據暫態的性能,比如臨時表和ETL期間(提取轉移和加載)。內存中的OLTP是一種內存優化的數據庫引擎,它集成到SQL Server引擎中,並針對事務處理進行了優化。
為了使用內存中的OLTP,您將一個重訪問的表定義為內存優化。內存優化的表是完全事務性的、持久的,並且可以使用與基於磁盤的表相同的方式訪問。一個查詢可以同時引用Hekaton內存優化表和基於磁盤的表。事務可以在Hekaton表和基於磁盤的表中更新數據。只引用內存優化表的存儲過程可以被本機編譯為機器代碼,以便進行進一步的性能改進。內存中的OLTP引擎是為一個非常高的會話而設計的
註意:在SQL Server 2014中引入了內存優化的OLTP表。不幸的是,它有許多限制,因此使用起來很不實際。在SQL Server 2016中,內存優化的表得到了極大的改進,並且大大減少了約束。在SQL Server 2016版本中,只有幾個限制仍然存在。本節提供的所有示例和技術只適用於SQL Server 2016版本。
在開始使用內存優化的表之前,必須使用一個memory最優化數據filegroup來創建一個數據庫。這個filegroup用於存儲SQL Server需要的數據和delta文件對來恢復內存優化的表。盡管創建它們的語法與創建常規filestream filegroup的語法幾乎相同,但它也必須指定包含memory優化數據選項。
創建
CREATE DATABASE [TestDB]
ON PRIMARY
( NAME = N‘TestDB_data‘, FILENAME = N‘C:\SQL2016\TestDB_data.mdf‘),
FILEGROUP [TestDBSampleDB_mod_fg] CONTAINS MEMORY_OPTIMIZED_DATA DEFAULT
( NAME = N‘TestDB_mod_dir‘, FILENAME = N‘C:\SQL2016\TestDB_mod_dir‘ , MAXSIZE = UNLIMITED)
LOG ON
( NAME = N‘TestDBSampleDB_log‘, FILENAME = N‘C:\SQL2016\TestDB_log.ldf‘ )
如果希望為現有數據庫啟用memory最優化數據選項,則需要使用memory優化數據選項創建一個filegroup,然後將文件添加到filegoup中。
ALTER DATABASE [TestDB] ADD FILEGROUP [TestDBSampleDB_mod_fg] CONTAINS MEMORY_OPTIMIZED_DATA; ALTER DATABASE [TestDB] ADD FILE (NAME=‘TestDB_mod_dir‘, FILENAME=‘C:\SQL2016\TestDB_mod_dir‘) TO FILEGROUP [TestDBSampleDB_mod_fg]; 執行下面的SQL代碼,以驗證是否啟用了一個數據庫內存優化數據選項。 USE TestDB SELECT g.name, g.type_desc, f.physical_name FROM sys.filegroups g JOIN sys.database_files f ON g.data_space_id = f.data_space_id WHERE g.type = ‘FX‘ AND f.type = 2 作為檢查memory優化數據的另一種選擇:打開數據庫屬性,選擇Filegroups,在memory優化數據選項中顯示filegroup名稱。 下面是基於磁盤的表和內存優化表之間的差異列表:MEMORY_OPTIMIZED property
–當訪問內存優化的表時,不需要從磁盤讀取這些頁面。所有的數據都存儲在內存中。
DURABILITY property
–內存優化的表可以是持久的(schemaanddata),也可以是非持久的(模式)。默認情況下,這些表是持久的(schemaanddata),這些持久表也滿足了所有其他事務需求;它們是原子的、孤立的、一致的。一組檢查點文件(數據和delta文件對),這些文件只用於恢復目的,是使用駐留在內存優化的文件組中的操作系統文件創建的,這些文件組跟蹤對持久表中的數據的更改。這些檢查點文件只是應用程序。非持久的,沒有記錄的,只使用一個選項模式。正如該選項所指出的,表模式將是持久的,即使數據不是。在事務處理過程中,這些表不需要任何IO操作,也不需要對這些表的檢查點文件進行任何操作。只有在SQL Server運行時,數據才可以在內存中使用。
Indexes
–沒有在內存優化的表上實現集群索引。索引不是作為傳統的b樹存儲的。內存優化的表支持散列索引,存儲為哈希表,其中有鏈表,將散列的所有行連接到相同的值和“範圍”索引,這些索引是使用特殊的bw樹存儲的。使用bw-tree的範圍索引可以用來快速查找範圍謂詞中的符合條件的行,就像傳統的b-樹一樣,但是它是用樂觀的並發控制設計的,沒有鎖定或鎖定。
將基於磁盤的磁盤遷移到內存優化的OLTP表
表是列和行的集合。為了將基於磁盤的表遷移到內存優化的表,有必要了解內存優化的表列數據類型的限制。
不支持以下數據類型:datetimeoffset
, geography
, geometry
, hierarchyid
, rowversion
, xml
, sql
_variant
, all User-Defined Types and all legacy LOB data types (including text
, ntext
, and image
)
支持數據類型包括:
bit
, tinyint
, smallint
, int
, bigint
. Numeric
and decimal
money
andsmallmoney
float
andreal
- date/time types:
datetime
,smalldatetime
,datetime2
,date
andtime
char
(n),varchar
(n),nchar
(n),nvarchar
(n),sysname
,varchar
(MAX) andnvarchar
(MAX)binary
(n),varbinary
(n) andvarbinary
(MAX)- Uniqueidentifier
創建內存優化的表的語法與創建基於磁盤的表的語法幾乎完全相同,有一些限制,以及一些必要的擴展。其中的一些區別是:
要設置 MEMORY_OPTIMIZED
= ON
The DURABILITY
property is set to SCHEMA_AND_DATA
or SCHEMA_ONLY
(SCHEMA_AND_DATA
is default)
The memory-optimized table must have a PRIMARY KEY
index. If HASH
index is selected for the primary key, then BUCKET_COUNT
must be specified.
在內存優化表中只允許包括主鍵在內的8個索引
IDENTITY
properties have to be set as seed = 1 and increment = 1 only.
在內存優化的表中不允許計算列(Computed Columns)
不加選擇地創建內存優化的表是一個壞主意。同時,對於OS和其他SQL服務器進程也需要內存,將盡可能多的表遷移到內存優化的表中並不是一個好主意。因為內存優化的表是用開放式並發控制設計的,沒有鎖定或被鎖,選擇轉換的最佳表應該是具有“鎖定和鎖定配置文件”(被檢測為會話“攔截器”的表)的表,其中包括最可寫的表(插入、更新和刪除)和最可讀的表,然而,這個列表對於遷移來說還不是很完整。但是,不應該遷移的表是靜態元數據表;違反了內存優化表的限制的表;表的行數更少。
在SQL Server 2016中,可以使用SQL Server
PowerShell生成一個遷移清單。在對象資源管理器中,右鍵單擊一個數據庫,然後單擊Start PowerShell;驗證以下提示出現,執行以下代碼:PS SQLSERVER:\SQL\{Instance Name}\DEFAULT\Databases\{DB Name}>
輸入以下命令(用您的目標文件夾路徑替換C:Temp。如果您喜歡使用更通用的方法$Env:Temp或$Env:報告輸出的路徑,然後驗證這些命令的PowerShell路徑。只需運行$Env:Temp或$Env:PowerShell命令窗口中的路徑,您的本地路徑將被返回)。清單PowerShell命令示例:
Save-SqlMigrationReport –FolderPath “C:\Temp”
註意:如果您需要在單個表上運行遷移報告,那麽就展開數據庫節點,展開表節點,右鍵單擊表,然後從彈出菜單中選擇Start PowerShell。
文件夾路徑將被創建,以防它不存在。遷移檢查表報告將為數據庫中的所有表和存儲過程生成,並且報告將出現在FolderPath指定的位置。因此,報告的文件夾路徑將被指定為PowerShell腳本中的FolderPath,以及檢查清單執行的數據庫名稱。在這個例子中,它是C:\Temp\Northwind.
檢查表報告可以指出,已經超過了內存優化表的一個或多個數據類型限制。但是,這並不意味著不能將表遷移到內存優化的表中。報告指出每一列是否滿足了成功的標準,如果沒有,則提示如果表對遷移很重要,那麽如何糾正問題。例如,一個數據庫有一個表testdisk。為了演示的目的,我們將在稍後的報告中看到這個表,其中包含了大量的遷移違規行為。
CREATE TABLE dbo.TEST_Disk( ID int IDENTITY(10000, 1), ProductID int NOT NULL, OrderQty int NOT NULL, SumOrder as ProductID + OrderQty, XMLData XML NULL, Description varchar(1000) SPARSE, StartDate datetime CONSTRAINT DF_TEST_DiskStart DEFAULT getdate() NOT NULL, ModifiedDate datetime CONSTRAINT DF_TEST_DiskEnd DEFAULT getdate() NOT NULL, CONSTRAINT PK_TEST_Disk_ID PRIMARY KEY CLUSTERED ( ID ) ) 遷移清單完成後,我們有以下報告:- XMLData column have XML data type
- SumOrder is Computed Column
- Description column is SPARSE
- ID have IDENTITY seed value 10000
根據這份報告,所有的違規行為都必須得到糾正,或者不能遷移表格。讓我們修正所有這些違規行為:
XMLData列將被轉換為nv(MAX)數據類型;這就是XML的本質。但是,當應用程序或數據庫沒有實現UNICODE時,可以考慮VARCHAR(MAX)數據類型。
SumOrder是計算的列,其中的值通過公式ProductID列進行計算,並使用OrderQty列(公式ProductID+OrderQty僅為演示目的而創建)。ProductID和OrderQty列都有int數據類型。因此,SumOrder列從ProductID和OrderQty列中繼承了int數據類型(如何糾正計算的列問題,將在“修復計算列問題”小節中解釋)。
Description列,為了糾正這個問題,只需刪除稀疏選項
ID
column IDENTITY
:將對應的seed value設置成1
在實現了所有的更正之後,testmemory內存優化表的DDL腳本將會是:
CREATE TABLE dbo.TEST_Memory( ID int IDENTITY(1, 1), ProductID int NOT NULL, OrderQty int NOT NULL, SumOrder int NULL, XMLData nvarchar(MAX) NULL, Description varchar(1000) NULL, StartDate datetime CONSTRAINT DF_TEST_MemoryStart DEFAULT getdate() NOT NULL, ModifiedDate datetime CONSTRAINT DF_TEST_MemoryEnd DEFAULT getdate() NOT NULL, CONSTRAINT PK_TEST_Memory_ID PRIMARY KEY NONCLUSTERED HASH ( ID )WITH (BUCKET_COUNT = 1572864) ) WITH ( MEMORY_OPTIMIZED = ON , DURABILITY = SCHEMA_AND_DATA ) 現在,我們需要將IDENTITY seed設置為10,000,但是,內存優化的表不支持DBCC命令來重置標識,設置IDENTITY_INSERT TEST_Memory ON將為我們完成 -- 1. Insert dummy row SET IDENTITY_INSERT TEST_Memory ON INSERT TEST_Memory (ID,ProductID, OrderQty, SumOrder) SELECT 10000, 1,1,1 SET IDENTITY_INSERT TEST_Memory OFF -- 2. Remove the record DELETE TEST_Memory WHERE ID = 10000 -- 3. Verify Current Identity SELECT TABLE_NAME, IDENT_SEED(TABLE_NAME) AS Seed, IDENT_CURRENT(TABLE_NAME) AS Current_Identity FROM INFORMATION_SCHEMA.TABLES WHERE OBJECTPROPERTY(OBJECT_ID(TABLE_NAME), ‘TableHasIdentity‘) = 1 AND TABLE_NAME = ‘TEST_Memory‘ 當所有這三個步驟都被應用時,您將把IDENTITY設置為10,000的所需值。 現在我們將加載一些測試數據。為了準備好大量的行,我們將通過下面的SQL腳本創建一個testdataload表,以便將100萬行裝載到表中。本文將介紹所有的SQL語法 ;With ZeroToNine (Digit) As (Select 0 As Digit Union All Select Digit + 1 From ZeroToNine Where Digit < 9), OneMillionRows (Number) As ( Select Number = SixthDigit.Digit * 100000 + FifthDigit.Digit * 10000 + FourthDigit.Digit * 1000 + ThirdDigit.Digit * 100 + SecondDigit.Digit * 10 + FirstDigit.Digit * 1 From ZeroToNine As FirstDigit Cross Join ZeroToNine As SecondDigit Cross Join ZeroToNine As ThirdDigit Cross Join ZeroToNine As FourthDigit Cross Join ZeroToNine As FifthDigit Cross Join ZeroToNine As SixthDigit ) Select Number+1 ID,ABS(CHECKSUM(NEWID())) % 50 ProductID, ABS(CHECKSUM(NEWID())) % 55 OrderQty , (SELECT Number+1 as ProductID,ABS(CHECKSUM(NEWID())) % 50 as OrderQty FROM master.dbo.spt_values as data WHERE type = ‘p‘ and data.number = v.number % 2047 FOR XML AUTO, ELEMENTS, TYPE ) XMLData INTO TEST_DataLoad From OneMillionRows v 當testdataload準備就緒時,讓我們為基於磁盤的和內存優化的表運行一個測試負載。服務器上有32個CPU;512GB的內存;核聚變(固態)驅動器。但是,內存優化的表執行的速度是磁盤表的兩倍多。 ---- Load disk-based table SET STATISTICS TIME ON; INSERT [dbo].[TEST_Disk] ( ProductID, OrderQty ) select ProductID, OrderQty from TEST_DataLoad SET STATISTICS TIME OFF; SQL Server Execution Times: CPU time = 5968 ms, elapsed time = 6322 ms. ---- Load the memory-optimized table SET STATISTICS TIME ON; INSERT [dbo].[TEST_Memory](ProductID, OrderQty, SumOrder) select ProductID, OrderQty,ProductID + OrderQty from TEST_DataLoad SET STATISTICS TIME OFF; SQL Server Execution Times: CPU time = 2500 ms, elapsed time = 2561 ms.
將一個基於磁盤的表遷移到SQL Server中的一個內存優化的表