In-Memory:在内存中创建临时表和表变量

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
简介:

在Disk-Base数据库中,由于临时表和表变量的数据存储在tempdb中,如果系统频繁地创建和更新临时表和表变量,大量的IO操作集中在tempdb中,tempdb很可能成为系统性能的瓶颈。在SQL Server 2016的内存(Memory-Optimized)数据库中,如果考虑使用内存优化结构来存储临时表,表变量,表值参数的数据,那么将完全消除IO操作的负载消耗,发挥大内存的优势,大幅提高数据库的性能。

在SQL Server 2016中,能够直接创建内存优化的表类型,表变量和表值参数的数据只存储在内存中;不能直接在内存中创建临时表,但是,SQL Server提供一个变通方法(Workaround),通过行级安全RLS(Row-Level-Security)控制,指定只有当前Session才能访问特定的数据,将内存优化表转换为Session级别的临时表,间接实现临时表的局部性和自动清空特性。

一,内存优化表类型(Memory-Optimized Table Type)

内存优化表类型定义的表变量,表值参数能够大幅提高效率(efficiency),有4个显著的特点:

  • 数据仅存储在内存中,在读写数据时,不会产生任何的IO消耗,消除了tempdb的竞争和利用率;
  • 必须有一个索引,Hash 或 Nonclustered 都行;每一个内存优化表必须创建一个索引;
  • 只需要指定启用内存优化:MEMORY_OPTIMIZED = ON,只持久化Schema;
  • 必须先创建表类型,后创建表值变量;

1,创建内存优化表类型

复制代码
CREATE TYPE dbo.TypeTable  
AS TABLE  
(  
Column1  INT NOT NULL,  
Column2  VARCHAR(10) NOT NULL,
INDEX idxName NONCLUSTERED(Column1)
)  
WITH(MEMORY_OPTIMIZED = ON); 
复制代码

2,创建内存优化表变量

declare @Table dbo.TypeTable 

二,创建“临时内存优化表”

在Disk-Base数据库中,局部临时表#temp的作用域是session,创建在tempdb中,一旦session生命周期结束,系统自动回收其存储空间。在SQL Server 2016中,不能直接在tempdb中创建内存优化表。要使用临时内存优化表,有一个变通的方法,在DB中创建内存优化表,通过Row-Level-Security控制Session能够访问的数据行,间接实现Session级别的临时表。

Step1,创建内存优化表,只持久化Table Schema

复制代码
CREATE TABLE dbo.SessionTempTable  
(  
    Column1 INT NOT NULL,  
    Column2 NVARCHAR(4000) NULL,  
    SpidFilter SMALLINT NOT NULL DEFAULT (@@spid),  
    INDEX ix_SpidFiler NONCLUSTERED (SpidFilter),  
    --INDEX ix_SpidFilter HASH (SpidFilter) WITH (BUCKET_COUNT = 64),  
    CONSTRAINT CHK_soSessionC_SpidFilter CHECK ( SpidFilter = @@spid ),  
)  
WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY);  
go 
复制代码

Step2,创建RLS,控制用户只能访问当前Session的数据

推荐为Predicate function 和 Security Policy创建单独的Schema,然后在该Schema下创建Predicate function 和 Security Policy,对于Predicate function必须使用 NATIVE_COMPLIATION选项创建。

复制代码
create schema rls
authorization dbo;

CREATE FUNCTION rls.fn_SpidFilter
(@SpidFilter smallint)  
RETURNS TABLE  
WITH SCHEMABINDING , NATIVE_COMPILATION  
AS  
RETURN  
    SELECT 1 AS fn_SpidFilter  
    WHERE @SpidFilter = @@spid;  
go

CREATE SECURITY POLICY rls.soSessionC_SpidFilter_Policy  
ADD FILTER PREDICATE rls.fn_SpidFilter(SpidFilter)  
ON dbo.SessionTempTable  
WITH (STATE = ON);  
go 
复制代码

Step3,使用内存优化临时表

  • 表名替换:使用 dbo.Temp 代替 #Temp;
  • 不能创建和删除临时表
    • 移除代码“create table #temp”,使用“delete from dbo.Temp”子句取代,将旧数据清空;
    • 移除代码“drop table #temp”,建议使用 “delete from dbo.Temp” 子句,在当前Session结束前将当前Session产生的数据清空,节省内存空间;

虽然临时表的使用和管理有点麻烦,但是,这点麻烦和大幅的性能提升来比,微不足道,建议使用内存优化表来代替临时表,体验飞一般的速度。

三,维护

1,通过RLS来创建内存临时表,如何清理临时表占用的内存空间?

试想出现异常,在当前Session将海量数据插入到临时表之后,Session异常终止,此时,Session没有来得及清空(Purge)临时表中的数据,这些数据仍然驻留在内存中。如果这种异常出现的频率很高,那么会导致内存优化表消耗大量的系统内存,必须有机制来定期清理临时表占用的内存空间。

step1,创建一个用户,RLSAdmin,授予db_owner的权限

--create User
create user RLSAdmin without login;
alter role db_owner
add member RLSAdmin;
go

step2,修改Predicate Function,如果用户是RLSAdmin,允许访问Base Table的所有数据行;

复制代码
--create predicate function
CREATE FUNCTION rls.fn_SpidFilter
(@SpidFilter smallint)  
RETURNS TABLE  
WITH SCHEMABINDING , NATIVE_COMPILATION  
AS  
RETURN  
    SELECT 1 AS fn_SpidFilter  
    WHERE @SpidFilter = @@spid or User_Name()='RLSAdmin';  
go
复制代码

step3,创建Schedule,定期检查数据库中的临时表,如果发现临时表中的存在未被清理的无效数据,那么删除该部分数据,释放内存。

复制代码
execute as RLSAdmin;

delete temp
from dbo.SessionTempTable temp
left join sys.dm_exec_sessions s
    on temp.SpidFilter=s.session_id 
        and s<>@@spid 
        and s.session_id>50
where s.session_id is null; 

revert;
复制代码

该脚本仅仅提供一种思路,在产品环境中,需要多测试,以防错误删除数据。

 

参考文档:

Memory-Optimized Table Variables

Faster temp table and table variable by using memory optimization

Improving temp table and table variable performance using memory optimization

CREATE TYPE (Transact-SQL)

Indexes for Memory-Optimized Tables

作者悦光阴
本文版权归作者和博客园所有,欢迎转载,但未经作者同意,必须保留此段声明,且在文章页面醒目位置显示原文连接,否则保留追究法律责任的权利。
分类: In-Memory






本文转自悦光阴博客园博客,原文链接:http://www.cnblogs.com/ljhdo/p/5040109.html,如需转载请自行联系原作者
相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS&nbsp;SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/sqlserver
目录
相关文章
|
2月前
|
存储 C语言 C++
动态内存分配与指向它的指针变量
动态内存分配与指向它的指针变量
20 1
|
4月前
|
存储 程序员 C语言
C语言:从内存出发,理解变量
C语言:从内存出发,理解变量
32 0
|
4月前
|
C++
vs中变量内存怎么看
vs中变量内存怎么看
|
1月前
|
存储 人工智能 Java
软件测试/人工智能|Python 变量解析:从基础概念到内存地址探究
软件测试/人工智能|Python 变量解析:从基础概念到内存地址探究
33 0
|
5月前
|
JavaScript 算法 前端开发
|
存储 JavaScript 前端开发
一篇文章带你搞定javaScript变量作用域和内存问题(变量,作用域,垃圾收集,管理内存)
一篇文章带你搞定javaScript变量作用域和内存问题(变量,作用域,垃圾收集,管理内存)
58 0
|
存储 C语言
(指针内容)当你申请一个变量,在这期间内存会发生什么?
(指针内容)当你申请一个变量,在这期间内存会发生什么?
94 0
(指针内容)当你申请一个变量,在这期间内存会发生什么?
|
存储 Linux C语言
C语言中变量在内存中的保存与访问
C语言中变量在内存中的保存与访问
|
存储 Web App开发 前端开发
重学JavaScript之变量、作用域和内存问题
重学JavaScript之变量、作用域和内存问题
|
Java
哪种JAVA的变量表达式使得变量a和变量b具有相同的内存引用地址????
哪种JAVA的变量表达式使得变量a和变量b具有相同的内存引用地址????
87 0