内存中用户定义的表,不在内存中?

Avi*_*i.M 10 sql-server in-memory user-defined-types sql-server-2014 memory-optimized-tables

我正在使用SQL Server 2014 CTP2,READ_COMMITTED_SNAPSHOT ON(我认为这对问题很重要).

我创建了一个In-Memory表类型(非常类似于technet博客,SQL Server 2014 In Memory OLTP:内存优化表类型和表变量),我有几个内存表.

在查询本身中,我在常规内存表和内存表类型之间有一个连接,充当过滤器,当我执行查询时,我收到此错误消息:"使用READ访问内存优化表的查询当数据库选项READ_COMMITTED_SNAPSHOT设置为ON时,COMMITTED隔离级别无法访问基于磁盘的表.使用表提示(例如WITH(SNAPSHOT))为内存优化表提供支持的隔离级别.

我正在写这个问题时删除了READ_COMMITTED_SNAPSHOT,但问题仍然存在,如果我创建了一个内存数据类型,并且这个特定类型将"永远不会溢出到磁盘",正如博客所说,为什么呢?服务器"看到"它作为"磁盘表?

为了清理,我尝试只使用In-Mem表进行连接并且它可以工作,只要表类型进来我就得到了错误.

更新:当我删除READ_COMMITTED_SNAPSHOT(现在已关闭)时,查询有效,但现在我已经丢失了多版本/无锁定/速度,我想听听另一个解决方案.

谢谢

重现步骤.

使用内存优化文件组创建数据库

CREATE DATABASE MemOptimized

GO

ALTER DATABASE MemOptimized 
    ADD FILEGROUP mofg 
    CONTAINS MEMORY_OPTIMIZED_DATA

GO

ALTER DATABASE MemOptimized 
    ADD FILE (  NAME = N'mofg', 
                FileName = N'C:\Program Files\Microsoft SQL Server\MSSQL12.MSSQLSERVER\MSSQL\DATA\MemOptimized.ndf') 
    TO FILEGROUP mofg
Run Code Online (Sandbox Code Playgroud)

创建一些对象

CREATE TYPE [dbo].[tType] AS TABLE(
        [C] [int] NOT NULL
        INDEX ix NONCLUSTERED HASH (C) WITH (BUCKET_COUNT = 8)
    ) WITH ( MEMORY_OPTIMIZED = ON )

CREATE TABLE [dbo].[tTable] (
        [C] [int] NOT NULL PRIMARY KEY NONCLUSTERED HASH WITH (BUCKET_COUNT = 8)
    ) WITH ( MEMORY_OPTIMIZED = ON )


INSERT INTO [dbo].[tTable] VALUES(1)

GO

CREATE PROC P
AS
    DECLARE @t [dbo].[tType]

    INSERT INTO @t
    VALUES     (1)

    SELECT *
    FROM   [dbo].[tTable] t
           INNER JOIN @t
             ON [@t].C = t.C 
Run Code Online (Sandbox Code Playgroud)

以下工作没有错误

ALTER DATABASE [MemOptimized] 
SET READ_COMMITTED_SNAPSHOT OFF WITH ROLLBACK IMMEDIATE

GO

USE MemOptimized

EXEC P 
Run Code Online (Sandbox Code Playgroud)

但是这个

ALTER DATABASE [MemOptimized] 
SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE

GO

USE MemOptimized

EXEC P 
Run Code Online (Sandbox Code Playgroud)

给出上面详述的错误

消息41359,级别16,状态0,过程P,行62使用READ COMMITTED隔离级别访问内存优化表的查询在数据库选项READ_COMMITTED_SNAPSHOT设置为ON时无法访问基于磁盘的表.使用表提示(例如WITH(SNAPSHOT))为内存优化表提供支持的隔离级别.

Mar*_*ith 10

我也看到了这一点.

启用RCSI时,默认读取提交级别的自动提交事务在将内存表类型的两个实例连接在一起时可以正常工作.

DECLARE @t1 [dbo].[tType]
DECLARE @t2 [dbo].[tType]

INSERT INTO @t1 VALUES (1);

INSERT INTO @t2 VALUES (1);

SELECT *
FROM   @t1
       JOIN @t2
         ON [@t1].C = [@t2].C 
Run Code Online (Sandbox Code Playgroud)

加入两个不同的"普通"内存优化表也可以正常工作,没有任何提示.

此外,将空的内存优化表类型加入到正常的内存优化表中也可以正常工作.

DECLARE @t [dbo].[tType];

SELECT *
FROM   [dbo].[tTable] t
        INNER JOIN @t
            ON [@t].C = t.C 
Run Code Online (Sandbox Code Playgroud)

但事实恰恰相反.只要内存表类型实例包含至少一行,然后将其连接到(空或其他)内存表中就会引发错误.

当数据库选项READ_COMMITTED_SNAPSHOT设置为ON时,使用READ COMMITTED隔离级别访问内存优化表的查询无法访问基于磁盘的表.使用表提示(例如WITH(SNAPSHOT))为内存优化表提供支持的隔离级别.

解决方案很简单,并在错误消息中指出.只需添加表提示即可WITH (SNAPSHOT)

DECLARE @t [dbo].[tType]

INSERT INTO @t
VALUES     (1)

SELECT *
FROM   [dbo].[tTable] t WITH(SNAPSHOT)
       INNER JOIN @t
         ON [@t].C = t.C
Run Code Online (Sandbox Code Playgroud)

或者一个不太精细的解决方案

ALTER DATABASE [MemOptimized] 
SET MEMORY_OPTIMIZED_ELEVATE_TO_SNAPSHOT = ON WITH ROLLBACK IMMEDIATE 
Run Code Online (Sandbox Code Playgroud)

这将为内存优化表设置隔离级别 SNAPSHOT(就像你WITH(SNAPSHOT)在每个内存优化表中包含提示一样)Source

据我所知,这些实际上都没有改变语义,在某些情况下省略提示的能力只是一种编程方便.

对于自动提交事务,隔离级别READ COMMITTED隐式映射到SNAPSHOT内存优化表.因此,如果TRANSACTION ISOLATION LEVEL会话设置设置为READ COMMITTED,则在访问内存优化表时,不必通过表提示指定隔离级别.资源

READ COMMITTED具有自动提交事务的内存优化表支持隔离级别.READ COMMITTED显式或隐式用户事务不支持.READ_COMMITTED_SNAPSHOT具有自动提交事务的内存优化表支持隔离级别,并且仅当查询不访问任何基于磁盘的表时才支持隔离级别 .资源

我不确定为什么这种不同的内存表类型的混合会导致这个特定的错误消息.我假设它只是一个CTP的假象,并且在RTM中,要么允许组合,要么更新错误消息和文档,以引用不仅仅基于磁盘的表.


小智 5

您看到的错误消息不正确.我们将内存优化表变量视为基于磁盘的表.此问题已在SQL Server 2014 RTM CU1中得到修复.

请注意,数据库选项READ_COMMITTED_SNAPSHOT不适用于内存优化表.它仅适用于基于磁盘的表.内存优化表始终是多版本的.