内存优化表, 以下简称内存表。
SQLServer2014的使用基本要求
1.?.Net?Framework?3.5?sp1?,
2.?.Net?Framework?4.0
3.?硬盘:>=6G
4.?内存:最小值:1G,推荐:>=4G
5.?CPU:最小值:x86:1.0?GHZ, x64:1.4?GHZ
6.?操作系统:Win7、WinServer2008?及以上?(WindowsServer2003不支持)
内存表基本要求
1.?64?位?Enterprise、Developer?或?Evaluation?版?SQL?Server?2014。(注:即只有64位系统才能使用内存优化表的功能,32位系统能安装SQL?Server2014,但无法使用内存表功能)
2.?SQL?Server?需要有足够的内存来保留内存优化表和索引中的数据。?若要容纳行版本,您应当提供两倍于内存优化表和索引预期大小的内存量。
内存表与磁盘表的DML对比
|
操作
磁盘表
内存表
Insert
数据页插入一行
为此表的存储桶加入一行,并加入时间戳
Delete
数据页删除
同上,也是加入一行。但只是一个专门记录删除操作的行。在相同的时间戳里,有两个数据文件,一个记录插入的行,一个记录删除的行,查询时第一个文件即去第二个文件即为真实表数据。
Update
Delete+Insert
Delete+Insert,删除行+插入行
Select
从数据页读
?
?
有回收线程不断回收同标识的旧行。
内存表比磁盘表快的原理
1.?内存读取比磁盘读取快;
2.?取消了锁,采用行版本机制,读取和更新不冲突。
内存表适合的场合
需要大量的并行操作的表
?
内存优化表的限制
1.?不支持的数据类型:varchar(max)、nvarchar(max)、image、xml、text、ntext、rowversion、datetimeoffset、geography、geometry、hierarchyid、sql_variant、UDT;
2.?每行的总字节数不得超过?8060?个字节;
3.?不支持外键或约束检查
4.?支持?IDENTITY(1,?1)。?但是不支持使用?IDENTITY(x,?y)(其中?x?!=?1?或?y?!=?1?)定义的标识列。
5.?不支持dml触发器
6.?内存优化表中的?(var)char?列必须使用代码页?1252?排序规则。?此限制不适用于?n(var)char?列。?下列代码检索所有?1252?排序规则:
select?*?from?sys.fn_helpcollations()??where?collationproperty(name,?'codepage')?=?1252;
7.?如果数据库排序规则不是代码页?1252?排序规则,则本机编译的存储过程不能使用?(var)char?类型的参数、局部变量或字符串常量。
8.?无法修改表结构,只能删除表再重建
9.?索引只能建hash非聚焦索引,?不能建聚焦索引。
10.?索引只能在建表时建立,不能重建索引。
?
具有内存优化对象(包括内存优化数据文件组)的数据库不支持以下?SQL?Server?功能。注:支持AlwaysOn
不支持的功能?
功能说明?
对内存优化表进行数据压缩。?
您可以使用数据压缩功能帮助压缩数据库中的数据并帮助减小数据库的大小。
对内存优化表和?HASH?索引进行分区。?
已分区表和已分区索引的数据划分为分布于一个数据库中多个文件组的单元。
数据库的内存优化数据文件组上的透明数据加密?(TDE)。?
“透明数据加密”(TDE)?可对数据和日志文件执行实时?I/O?加密和解密。
可在拥有内存中?OLTP?对象的数据库上启用?TDE。??如果启用?TDE,则内存中?OLTP?日志记录会被加密。?即使在数据库上启用了?TDE,也不会对耐久性表的检查点文件加密。
复制?
对订阅服务器上内存优化表进行的事务复制之外的其他复制配置与引用内存优化表的表或视图不兼容。??如果存在内存优化文件组,则不支持使用?sync_mode=’database?snapshot’?的复制。
多个活动的结果集?(MARS)?
内存优化表不支持多个活动结果集?(MARS)。??此错误还可能指示使用了链接服务器。?链接服务器可以使用?MARS。?内存优化表不支持链接服务器。?请直接连接到托管内存优化表的服务器和数据库。
镜像?
“数据库镜像”是一种提高?SQL?Server?数据库可用性的解决方案。
链接服务器?
?
大容量日志记录?
无论数据库处于什么恢复模式,都将始终完整记录针对持久内存优化表的所有操作的日志。?
最小日志记录?
内存优化表不支持最小日志记录。??
更改跟踪?
可在包含内存中?OLTP?对象的数据库上启用更改跟踪。??但是,在内存优化表上的更改不会被跟踪。
DDL?触发器?
内存中?OLTP?表和本机编译的存储过程不支持数据库级别和服务器级别的?DDL?触发器。?
变更数据捕获?(CDC)?
不应在包含内存中?OLTP?对象的数据库上启用?CDC,因为它会阻止某些操作,如?DROP。?
?
内存表与磁盘表DML性能对比
测试环境:
CPU:?Intel?Core?i3-3240?3.40GHz?
内存:4.00GB(3.86GB可用)
系统类型:?Windows?Server?2008?R2?Enterprise?64位
?
两次测试取平均值,?测试SQL见后面的附录
操作
记录数
磁盘表
内存表
内存表+本地编译的存储过程
Insert
1000000
242.642?s
222.411?s
2.181?s
Delete
1000000
199.538?s
342.365?s
0.866?s
Update
1000000
201.310?s
361.827?s
3.724?s
Select
1000000
8.898?s
9.628?s
8.999?s
?
总结
效率:内存表对比普通的磁盘表, 在增、删、改方面有非常大的优势, 甚至达到了上百倍!但查询方面并没有太大的区别。
?
可行性:内存表的限制比较大,比如数据库用了内存表之后就不能使用复制、镜像、链接服务器, 内存表也不能使用触发器、约束, 每行的字节数不能超过8060字节, 内存表的结构和索引建立之后就不能修改等等。?而且必须配合本地编译的存储过程效率才能提升。仅适用于数据库不需要被限制的功能(复制、镜像等), 而且表的增、删、改非常频繁的情况。
?
SqlServer2014内存表对比oracle?12C的?inmemory?选件, 后者易用性更高(?alter?table?tableName?inmemory?即可),?而且其使用对比普通表没有太大区别, 限制很少。
?
SqlServer2014内存表感觉有些鸡肋, 期待下一版的改进。
附录
以下是性能评测SQL:
------------------------- 1. 建库 -------------------------
USE [master]
GO
if exists(select * from sysdatabases where name='DB_TEST_MEMTB')
DROP DATABASE DB_TEST_MEMTB
go
CREATE DATABASE [DB_TEST_MEMTB]
ON PRIMARY
(
NAME = N'DB_TEST_MEMTB_DATA',FILENAME = N'e:dbtestDB_TEST_MEMTB_DATA.mdf',SIZE = 512000KB,MAXSIZE = UNLIMITED,FILEGROWTH = 1024KB
),--下面的文件就是数据流文件了
FILEGROUP [MEM_DIR] CONTAINS MEMORY_OPTIMIZED_DATA DEFAULT
(
NAME = N'DB_TEST_MEMTB_DIR',FILENAME =N'e:dbtestDB_TEST_MEMTB_DIR',MAXSIZE = UNLIMITED
)
LOG ON
(
NAME = N'DB_TEST_MEMTB_LOG',FILENAME = N'e:dbtestDB_TEST_MEMTB_LOG.ldf',MAXSIZE = 2048GB,FILEGROWTH = 1024KB
)
GO
------------------------- 2. 建表和本地编译存储过程 -------------------------
USE DB_TEST_MEMTB
GO
-- 1. 建立普通磁盘表
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[t_disk]') AND type in (N'U'))
DROP TABLE [dbo].[t_disk]
GO
create table [t_disk]
(
c1 int not null primary key,c2 nchar(48) not null
)
go
-- 2. 建立内存优化表 (后面的测试不使用本地编译存储过程)
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[t_mem]') AND type in (N'U'))
DROP TABLE [dbo].[t_mem]
GO
create table [t_mem]
(
c1 int not null primary key nonclustered hash with (bucket_count=10000000),c2 nchar(48) not null
) with (memory_optimized=on,durability = schema_and_data)
GO
-- 3.0 建立内存优化表 (后面的测试使用本地编译存储过程 NATIVE_COMPILATION)
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[t_mem_nc]') AND type in (N'U'))
DROP TABLE [dbo].t_mem_nc
GO
create table t_mem_nc
(
c1 int not null primary key nonclustered hash with (bucket_count=10000000),durability = schema_and_data)
GO
-- 3.1 本地编译存储过程_insert
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Proc_t_mem_nc_Insert]') AND type in (N'P',N'PC'))
DROP PROCEDURE [dbo].[Proc_t_mem_nc_Insert]
GO
CREATE PROCEDURE [Proc_t_mem_nc_Insert]
@rowcount int,@c nchar(48)
WITH NATIVE_COMPILATION,SCHEMABINDING,EXECUTE AS OWNER
AS
BEGIN ATOMIC
WITH (TRANSACTION ISOLATION LEVEL = SNAPSHOT,LANGUAGE = N'us_english')
declare @i int = 1
while @i <= @rowcount
begin
INSERT INTO [dbo].t_mem_nc values (@i,@c)
set @i += 1
end
END
GO
-- 3.2 本地编译存储过程_delete
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Proc_t_mem_nc_delete]') AND type in (N'P',N'PC'))
DROP PROCEDURE [dbo].[Proc_t_mem_nc_delete]
GO
CREATE PROCEDURE [Proc_t_mem_nc_delete]
@rowcount int
WITH NATIVE_COMPILATION,LANGUAGE = N'us_english')
DECLARE @i INT = 1
while @i<=@rowcount
begin
DELETE FROM dbo.t_mem_nc WHERE c1=@i
set @i += 1
end
END
GO
-- 3.3 本地编译存储过程_update
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Proc_t_mem_nc_update]') AND type in (N'P',N'PC'))
DROP PROCEDURE [dbo].[Proc_t_mem_nc_update]
GO
CREATE PROCEDURE [Proc_t_mem_nc_update]
@rowcount INT,LANGUAGE = N'us_english')
DECLARE @i INT = 1
while @i<=@rowcount
begin
UPDATE dbo.t_mem_nc SET c2=@c WHERE c1=@i
set @i += 1
end
END
GO
-- 3.4 本地编译存储过程_select
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Proc_t_mem_nc_select]') AND type in (N'P',N'PC'))
DROP PROCEDURE [dbo].[Proc_t_mem_nc_select]
GO
CREATE PROCEDURE [Proc_t_mem_nc_select]
WITH NATIVE_COMPILATION,LANGUAGE = N'us_english')
SELECT c1,c2 FROM dbo.t_mem_nc
END
GO
------------------------- 3. 效率评测 -------------------------
DECLARE @i INT=1,@iMax INT = 1000000 --最大一百万条记录
DECLARE @v NCHAR(48)='123456789012345678901234567890123456789012345678'
DECLARE @t DATETIME2 = sysdatetime()
--3.1 insert
--
set nocount on
while @i<=@iMax
begin
insert into t_disk (c1,c2) values(@i,@v)
set @i+=1
end
select 'insert (t_disk): '+ convert(varchar(10),datediff(ms,@t,sysdatetime()))
--
set @i=1
set @t=SYSDATETIME()
while @i<=@iMax
begin
insert into t_mem (c1,@v)
set @i+=1
end
select 'insert (t_mem): '+ convert(varchar(10),sysdatetime()))
--
set @t=SYSDATETIME()
exec [Proc_t_mem_nc_Insert]
@rowcount=@iMax,@c=@v
select 'insert (t_mem_nc): '+ convert(varchar(10),sysdatetime()))
--结果:
--insert (t_disk): 242111
--insert (t_mem): 221358
--insert (t_mem_nc): 2147
--insert (t_disk): 243174
--insert (t_mem): 223465
--insert (t_mem_nc): 2214
--3.2 update
--时间较长,故分段执行另设变量
DECLARE @u INT=1,@uMax INT = 1000000 --最大一百万条记录
DECLARE @uv NCHAR(48)='1234567890123456789012345678901234567890abcdefgh'
DECLARE @ut DATETIME2 = sysdatetime()
set nocount on
while @u<=@uMax
begin
update t_disk set c2=@uv where c1=@u
set @u+=1
end
select 'update (t_disk): '+ convert(varchar(10),@ut,sysdatetime()))
--
set @u=1
set @ut=SYSDATETIME()
while @u<=@uMax
begin
update t_mem set c2=@uv where c1=@u
set @u+=1
end
select 'update (t_mem): '+ convert(varchar(10),sysdatetime()))
--
set @ut=SYSDATETIME()
exec [Proc_t_mem_nc_Update]
@rowcount=@uMax,@c=@uv
select 'update (t_mem_nc): '+ convert(varchar(10),sysdatetime()))
--update (t_disk): 199369
--update (t_mem): 368297
--update (t_mem_nc): 3715
--update (t_disk): 203251
--update (t_mem): 355356
--update (t_mem_nc): 3732
--3.3 select
DECLARE @st DATETIME2 = sysdatetime()
set nocount on
--
select c1,c2 from t_disk
select 'select (t_disk): '+ convert(varchar(10),@st,sysdatetime()))
set @st=SYSDATETIME()
select c1,c2 from t_mem
select 'select (t_mem): '+ convert(varchar(10),sysdatetime()))
set @st=SYSDATETIME()
exec Proc_t_mem_nc_select
select 'select (t_mem_nc): '+ convert(varchar(10),sysdatetime()))
--select (t_disk): 8934
--select (t_mem): 9278
--select (t_mem_nc): 8889
--select (t_disk): 8861
--select (t_mem): 9978
--select (t_mem_nc): 9108
--3.4 delete
--时间较长,故分段执行另设变量
DECLARE @d INT=1,@dMax INT = 1000000 --最大一百万条记录
DECLARE @dt DATETIME2 = sysdatetime()
set nocount on
while @d<=@dMax
begin
delete from t_disk where c1=@d
set @d+=1
end
select 'delete (t_disk): '+ convert(varchar(10),@dt,sysdatetime()))
--
set @d=1
set @dt=SYSDATETIME()
while @d<=@dMax
begin
delete from t_mem where c1=@d
set @d+=1
end
select 'delete (t_mem): '+ convert(varchar(10),sysdatetime()))
--
set @dt=SYSDATETIME()
exec [dbo].[Proc_t_mem_nc_delete] @rowcount=@dMax
select 'delete (t_mem_nc): '+ convert(varchar(10),sysdatetime()))
--delete (t_disk): 199438
--delete (t_mem): 342959
--delete (t_mem_nc): 928
--delete (t_disk): 199637
--delete (t_mem): 341771
--delete (t_mem_nc): 803
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!