将一个基于磁盘的表迁移到SQL Server中的一个内存优化的表

Posted 秋天的林子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将一个基于磁盘的表迁移到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 and smallmoney
  • float and real
  • date/time types: datetime, smalldatetime, datetime2, date and time
  • char(n), varchar(n), nchar(n), nvarchar(n), sysname, varchar(MAX) and nvarchar(MAX)
  • binary(n), varbinary(n) and varbinary(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-SqlMigrationReportFolderPathC:\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;512
GB的内存;核聚变(固态)驱动器。但是,内存优化的表执行的速度是磁盘表的两倍多。
---- 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中的一个内存优化的表的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 SSMA(用于访问 SQL Server)将具有不同列的表迁移到现有表中?

sql语句将Excel中的一列批量更新到sql server中的一列中?

将 SQL Server 数据库迁移到 MongoDB

sql server 临时库文件太大 迁移tempdb数据库

将 SQL Server 上的存储过程迁移到 HPL/SQL(Hadoop 生态系统)

如何把sqlserver数据迁移到mysql数据库及需要注意事项