MS-SQL 是不是支持内存表?

Posted

技术标签:

【中文标题】MS-SQL 是不是支持内存表?【英文标题】:Does MS-SQL support in-memory tables?MS-SQL 是否支持内存表? 【发布时间】:2010-09-06 20:52:46 【问题描述】:

最近,我开始更改我们的一些应用程序以支持 MS SQL Server 作为替代后端。

我遇到的一个兼容性问题是使用 mysql 的 CREATE TEMPORARY TABLE 创建内存表,这些表保存数据以便在会话期间非常快速地访问,而无需永久存储。

MS SQL 中的等价物是什么?

一个要求是我需要能够像使用任何其他表一样使用临时表,尤其是 JOIN 它与永久表。

【问题讨论】:

我希望您知道,在 MySQL 中,用户创建的临时表默认情况下不在内存中!仅当您在 CREATE TABLE 语句中指定 ENGINE=MEMORY 时,该表才会在内存中。否则,临时表将使用默认存储引擎创建,很可能是 MyISAM 或 INNODB,并保存在磁盘上。不要将用户创建的表与 MySQL 在复杂连接期间创建的内部临时表混淆。如果可能,它们会在内存中创建。 【参考方案1】:

您可以创建表变量(在内存中),以及两种不同类型的临时表:

--visible only to me, in memory (SQL 2000 and above only)
declare @test table (
    Field1 int,
    Field2 nvarchar(50)
);

--visible only to me, stored in tempDB
create table #test (
    Field1 int,
    Field2 nvarchar(50)
)

--visible to everyone, stored in tempDB
create table ##test (
    Field1 int,
    Field2 nvarchar(50)
)

编辑:

根据反馈,我认为这需要澄清一下。

#table##table 将始终位于 TempDB 中。

@Table 变量通常会在内存中,但不保证会在内存中。 SQL 根据查询计划决定,如果需要,使用 TempDB。

【讨论】:

【参考方案2】:

@基思

这是一个常见的误解:表变量不一定存储在内存中。事实上,SQL Server 决定是将变量保留在内存中还是将其溢出到 TempDB。没有可靠的方法(至少在 SQL Server 2005 中)来确保将表数据保存在内存中。更多详细信息请查看here

【讨论】:

【参考方案3】:

您可以在 SQL Server 2005 中声明一个“表变量”,如下所示:

declare @foo table (
    Id int,
    Name varchar(100)
);

然后你就像一个变量一样引用它:

select * from @foo f
    join bar b on b.Id = f.Id

无需删除它 - 当变量超出范围时它会消失。

【讨论】:

【参考方案4】:

MS SQL Server 2014 可以实现。

见:http://msdn.microsoft.com/en-us/library/dn133079.aspx

这是一个 SQL 生成代码示例(来自 MSDN):

-- create a database with a memory-optimized filegroup and a container.
CREATE DATABASE imoltp 
GO

ALTER DATABASE imoltp ADD FILEGROUP imoltp_mod CONTAINS MEMORY_OPTIMIZED_DATA 
ALTER DATABASE imoltp ADD FILE (name='imoltp_mod1', filename='c:\data\imoltp_mod1') TO FILEGROUP imoltp_mod 
ALTER DATABASE imoltp SET MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT=ON
GO

USE imoltp
GO


-- create a durable (data will be persisted) memory-optimized table
-- two of the columns are indexed
CREATE TABLE dbo.ShoppingCart ( 
  ShoppingCartId INT IDENTITY(1,1) PRIMARY KEY NONCLUSTERED,
  UserId INT NOT NULL INDEX ix_UserId NONCLUSTERED HASH WITH (BUCKET_COUNT=1000000), 
  CreatedDate DATETIME2 NOT NULL, 
  TotalPrice MONEY
  ) WITH (MEMORY_OPTIMIZED=ON) 
GO

 -- create a non-durable table. Data will not be persisted, data loss if the server turns off unexpectedly
CREATE TABLE dbo.UserSession ( 
  SessionId INT IDENTITY(1,1) PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT=400000), 
  UserId int NOT NULL, 
  CreatedDate DATETIME2 NOT NULL,
  ShoppingCartId INT,
  INDEX ix_UserId NONCLUSTERED HASH (UserId) WITH (BUCKET_COUNT=400000) 
  ) WITH (MEMORY_OPTIMIZED=ON, DURABILITY=SCHEMA_ONLY) 
GO

【讨论】:

【参考方案5】:

一个很好的blog post here,但基本上是在本地临时表前面加上#,在全局临时表前面加上## - 例如

CREATE TABLE #localtemp

【讨论】:

【参考方案6】:

我了解您想要实现的目标。欢迎来到各种数据库的世界!

SQL server 2000 支持通过在表名前加上 # 前缀来创建临时表,使其成为本地可访问的临时表(会话本地)并在表名前加上 ##,用于全局可访问的临时表,例如 #MyLocalTable 和##MyGlobalTable 分别。

SQL server 2005 及更高版本同时支持临时表(本地、全局)和表变量 - 注意 SQL 2008 中表变量的新功能并发布两个!临时表和表变量的区别并没有那么大,而在于数据库服务器处理它们的方式。

我不想谈论像 7、6 这样的旧版本 SQL Server,尽管我曾与他们合作过,而且无论如何我都是从那里来的 :-)

通常认为表变量总是驻留在内存中,但这是错误的。根据内存使用情况和数据库服务器的事务量,表变量的页面可能会从内存中导出并写入 tempdb 中,其余的处理会在那里进行(在 tempdb 中)。

请注意,tempdb 是实例上的数据库,本质上没有永久对象,但它负责处理涉及诸如排序等辅助事务的工作负载,以及其他临时性质的处理工作。另一方面,表变量(通常具有较小的数据)保存在内存 (RAM) 中,使其访问速度更快,因此与临时表相比,在使用具有较小数据的表变量时使用 tempdb 驱动器的磁盘 IO 总是更少登录 tempdb。

表变量不能被索引,而临时表(本地和全局)可以被索引以便在数据量很大的情况下更快地处理。因此,在通过临时事务处理更大数据量的情况下,您知道自己的选择。还值得注意的是,仅表变量上的事务不会被记录并且无法回滚,而在临时表上完成的事务可以回滚!

总之,表变量更适合较小的数据,而临时表更适合临时处理的较大数据。如果您还希望使用事务块进行适当的事务控制,表变量不是回滚事务的选项,因此在这种情况下您最好使用临时表。

最后,临时表总是会增加磁盘 IO,因为它们总是使用 tempdb,而表变量可能不会增加它,这取决于内存压力级别。

如果您需要有关如何调整 tempdb 以获得更快的性能以达到 100% 以上的提示,请告诉我!

【讨论】:

克里斯,你为什么不设置一个 SO 帐户? @Chris - 请在帖子末尾留下宗教标语。此外,自我宣传的内容属于您的个人资料,而不是帖子的末尾。【参考方案7】:

你想要的语法是:

创建表#tablename

# 前缀将表标识为临时表。

【讨论】:

【参考方案8】:

创建表#tmptablename

使用井号/井号前缀

【讨论】:

以上是关于MS-SQL 是不是支持内存表?的主要内容,如果未能解决你的问题,请参考以下文章

内存优化表(EF 核心 5)不支持保存点

ms-sql关联表操作

如何在查询中加入 MS-SQL 和 MySQL 表?

如何一次性同步内存中的集合与其后备数据库表

如何确定一个链表是不是有一个仅使用两个内存位置的循环

从内存而不是表中获取数据