SQL 2014内存优化表
2014-04-18 13:08
197 查看
SQL2014发布后,最令我感兴趣的是列索引的改进和新增的内存优化表。前者让2012中鸡肋的新功能具备了真正用于实际环境的可能,后者则很可能是又一个激动人心的新鸡肋。
本文介绍内存优化表的简单基础、示例代码及初体验。 计划再用三篇文章介绍内存优化表的索引、架构和备份还原。
总体上来说,内存优化表除了本身存在于SQL SERVER数据库中,混身上下的全部零件都与之前版本的磁盘表(即2014前的所有SQL SERVER表)没有半毛钱关系,完全是新概念新架构。以下几点能证明我的观点:
1.它不存放在数据页中
2.它的表物理结构和磁盘表不同
3.它的索引结构和使用方法跟磁盘表不同
4.它没有锁
5.它的事务处理方式与磁盘表不同
6.它比磁盘表快的多
7.它霸占内存
首先我们从了解内存优化表(以下简称内存表)的结构开始。
与传统的磁盘表不同,内存表的数据不保存在mdf文件中(其实我个人非常喜欢用.avi替代.mdf当后缀),而是由一堆数据流文件和内存中的一群钉子户组成。当你创建数据库时,如果要在库中使用内存表,你就需要先为数据库指定一个目录存放内存表的数据流文件。当创建内存表时,你又需要为它指定占用的内存空间大小(存储桶数)。在满足了这两个条件后,数据库启动后会在内存中为所有内存表分配同一个固定的空间,并从数据文件中加载所有表数据到这个空间里。所以,内存表的读取与磁盘表的加载数据页读取根本就是两个概念,它没有加载数据页的概念,所有数据都在内存里,它甚至没有页的概念,同一个数据文件中可能存在N个表的数据。数据页头的标识只有用于查找数据更新时间的两个时间戳。
可以说,内存表的主体实际是内存空间中的数据。磁盘上的数据流文件则可以认为是它的备份文件,由单独的线程定期更新,并在数据库启动或恢复时用于还原内存表。
然后我们来看一下内存表的DML底层实现。先说磁盘表,SELECT是去数据页里读数据,INSERT是往数据页中增加一行数据,DELETE是从数据页中擦除,UPDATE是DELETE+INSERT。而内存表是没有数据页的概念的,那它是如何实现这些操作的呢?
当你向内存表中INSERT时,会向内存空间中为这个表分配的存储桶中加入一行,并记录插入的时间戳。
当你从内存表中DELETE时,会向内存空间中为这个表分配的存储桶中加入一行,并记录插入的时间戳。。。。不过不是上面那种行,而是一个专门记录删除操作的行。在某一个相同的时间戳段里,存在两个数据文件,一个记录这段时间内插入的行,一个记录这段时间内删除的行,查询时把这个表之前的所有文件读出来,第一个文件减掉第二个文件,就是真实的表数据了。
当你对内存表UPDATE时,会做什么操作呢?其实还是DELETE+INSERT。它会先记录一个删除行,再记录一个插入行。由于新行的标识与原行相同,版本更新,UPDATE结束后读取这行就都是从新行读了。
看起来是不是有点眼熟?没错,就是快照隔离级别,只不过由于内存空间很金贵,所以还有一个擦屁股线程不断的合并回收无效行当一个行被同标识的新行取代,且没有活动事务时,就会被回收合并,作为可用空间使用。
由于内存表采用行版本的机制,因此读取和更新并不冲突,本来在内存中的读取就够快了,无非是读到的版本不够新,不会出现更新被大量读取阻塞的现象。又由于内存预留机制和数据流的IO写入方式,使磁盘IO几乎不会出现瓶颈,因此,内存表非常适合大量的并行操作(相对磁盘表,没有和NOSQL数据库叫板的意思哥)。事实上,由于空间的限制,也只适合这种业务场景。。。。
说了一大堆,我们还是看一下实际的例子,理解起来更直观。
首先你需要装上2014(废话),然后新建一个数据库,指定一个数据流文件存储目录
SQL code?
然后,我是用MS的示例代码建的表
SQL code?
建表语法就和以往不同,需要指定好多东西。关注这两句:
c1 int not null primary key nonclustered hash with (bucket_count=1000000)
with (memory_optimized=on, durability = schema_and_data)
memory_optimized=on指定表为内存优化表,durability = schema_and_data指定内存表同时存储于数据流文件中,如果是schema_only,就不存到磁盘中,可以理解成更快的、能建索引的全局表变量。
列里的hash关键字指定为c1列建立hash索引,关于内存表的索引在后面的文章中介绍。
跳过存储过程,我们直接看性能测试代码:
SQL code?
上面代码的功能简单来说就是往磁盘表中插入1W条数据、往内存表中插入1W条数据、往内存表中通过存储过程插入1W条数据。跳过第一次运行,在我机器上跑的结果是:
Disk-based table and interpreted Transact-SQL: 1022 ms
memory-optimized table w/ hash index and interpreted Transact-SQL: 784 ms
memory-optimized table w/hash index and native SP:248 ms
可以看到,在跳过了编译后,单条数据的操作性能几乎翻了5倍,提升非常大。
本文介绍内存优化表的简单基础、示例代码及初体验。 计划再用三篇文章介绍内存优化表的索引、架构和备份还原。
总体上来说,内存优化表除了本身存在于SQL SERVER数据库中,混身上下的全部零件都与之前版本的磁盘表(即2014前的所有SQL SERVER表)没有半毛钱关系,完全是新概念新架构。以下几点能证明我的观点:
1.它不存放在数据页中
2.它的表物理结构和磁盘表不同
3.它的索引结构和使用方法跟磁盘表不同
4.它没有锁
5.它的事务处理方式与磁盘表不同
6.它比磁盘表快的多
7.它霸占内存
首先我们从了解内存优化表(以下简称内存表)的结构开始。
与传统的磁盘表不同,内存表的数据不保存在mdf文件中(其实我个人非常喜欢用.avi替代.mdf当后缀),而是由一堆数据流文件和内存中的一群钉子户组成。当你创建数据库时,如果要在库中使用内存表,你就需要先为数据库指定一个目录存放内存表的数据流文件。当创建内存表时,你又需要为它指定占用的内存空间大小(存储桶数)。在满足了这两个条件后,数据库启动后会在内存中为所有内存表分配同一个固定的空间,并从数据文件中加载所有表数据到这个空间里。所以,内存表的读取与磁盘表的加载数据页读取根本就是两个概念,它没有加载数据页的概念,所有数据都在内存里,它甚至没有页的概念,同一个数据文件中可能存在N个表的数据。数据页头的标识只有用于查找数据更新时间的两个时间戳。
可以说,内存表的主体实际是内存空间中的数据。磁盘上的数据流文件则可以认为是它的备份文件,由单独的线程定期更新,并在数据库启动或恢复时用于还原内存表。
然后我们来看一下内存表的DML底层实现。先说磁盘表,SELECT是去数据页里读数据,INSERT是往数据页中增加一行数据,DELETE是从数据页中擦除,UPDATE是DELETE+INSERT。而内存表是没有数据页的概念的,那它是如何实现这些操作的呢?
当你向内存表中INSERT时,会向内存空间中为这个表分配的存储桶中加入一行,并记录插入的时间戳。
当你从内存表中DELETE时,会向内存空间中为这个表分配的存储桶中加入一行,并记录插入的时间戳。。。。不过不是上面那种行,而是一个专门记录删除操作的行。在某一个相同的时间戳段里,存在两个数据文件,一个记录这段时间内插入的行,一个记录这段时间内删除的行,查询时把这个表之前的所有文件读出来,第一个文件减掉第二个文件,就是真实的表数据了。
当你对内存表UPDATE时,会做什么操作呢?其实还是DELETE+INSERT。它会先记录一个删除行,再记录一个插入行。由于新行的标识与原行相同,版本更新,UPDATE结束后读取这行就都是从新行读了。
看起来是不是有点眼熟?没错,就是快照隔离级别,只不过由于内存空间很金贵,所以还有一个擦屁股线程不断的合并回收无效行当一个行被同标识的新行取代,且没有活动事务时,就会被回收合并,作为可用空间使用。
由于内存表采用行版本的机制,因此读取和更新并不冲突,本来在内存中的读取就够快了,无非是读到的版本不够新,不会出现更新被大量读取阻塞的现象。又由于内存预留机制和数据流的IO写入方式,使磁盘IO几乎不会出现瓶颈,因此,内存表非常适合大量的并行操作(相对磁盘表,没有和NOSQL数据库叫板的意思哥)。事实上,由于空间的限制,也只适合这种业务场景。。。。
说了一大堆,我们还是看一下实际的例子,理解起来更直观。
首先你需要装上2014(废话),然后新建一个数据库,指定一个数据流文件存储目录
SQL code?
SQL code?
c1 int not null primary key nonclustered hash with (bucket_count=1000000)
with (memory_optimized=on, durability = schema_and_data)
memory_optimized=on指定表为内存优化表,durability = schema_and_data指定内存表同时存储于数据流文件中,如果是schema_only,就不存到磁盘中,可以理解成更快的、能建索引的全局表变量。
列里的hash关键字指定为c1列建立hash索引,关于内存表的索引在后面的文章中介绍。
跳过存储过程,我们直接看性能测试代码:
SQL code?
Disk-based table and interpreted Transact-SQL: 1022 ms
memory-optimized table w/ hash index and interpreted Transact-SQL: 784 ms
memory-optimized table w/hash index and native SP:248 ms
可以看到,在跳过了编译后,单条数据的操作性能几乎翻了5倍,提升非常大。
相关文章推荐
- 利用Access登录Mysql数据库
- 精妙SQL语句收集
- 基于Swoole扩展开发异步高性能的MySQL代理服务器
- mysql 授权管理
- 详解Oracle临时表的几种用法及意义
- MySql数据库出现的错误
- SQL通用版分页存储过程
- 简单的java连接MongoDB实例
- mysql 高级之权限-用户权限
- jdbc在操作oracle海量数据的时候用ResultSet获取所有的返回数据出现内存溢出(转)
- 数据库-设计-数据库表字段类型设计标准
- sqlserver2008安装遇到的问题
- Oracle BI 管理工具 数据源 导入元数据 无法显示完整结构 解决办法
- sqlite判断表是否存在
- oracle 的dbms_application_info包
- 配置PL/SQL 及 出现中文乱码的解决方法
- mysql数据库引擎介绍
- [MYSQL]时间毫秒数转换
- MongoDB 介绍及Windows下安装
- C# 利用*.SQL文件自动建库建表等的类