内存优化表-INSERT比SSD慢

Pit*_*DBA 8 sql-server performance query-performance memory-optimized-tables

我已经观察到,将数据插入内存优化表比在5-SSD条带集上对基于磁盘的表进行等效的并行插入要慢得多。

--DDL for Memory-Optimized Table    
CREATE TABLE [MYSCHEMA].[WIDE_MEMORY_TABLE]
        (
        [TX_ID] BIGINT NOT NULL
        , [COLUMN_01] [NVARCHAR](10) NOT NULL
        , [COLUMN_02] [NVARCHAR] (10) NOT NULL
        --etc., about 100 columns
        --at least one index is required for Memory-Optimized Tables
        , INDEX IX_WIDE_MEMORY_TABLE_ENTITY_ID HASH (TX_ID) WITH (BUCKET_COUNT=10000000)
        )
        WITH (MEMORY_OPTIMIZED=ON, DURABILITY=SCHEMA_ONLY)

--DDL for Disk-Based Table
CREATE TABLE [MYSCHEMA].[WIDE_DISK_TABLE]
        (
        [TX_ID] BIGINT NOT NULL
        , [COLUMN_01] [NVARCHAR](10) NOT NULL
        , [COLUMN_02] [NVARCHAR] (10) NOT NULL
        --etc., about 100 columns
        --No indexes
        ) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)

对于此特定测试,我将以25,000个为一组将10,000,000行批量添加到该表中。对于内存优化表,该语句如下所示:

    --Insert to Memory-Optimized Table 
    INSERT INTO
        WIDE_MEMORY_TABLE
        (
        TX_ID
        , COLUMN_01
        , COLUMN_02
        --etc., about 100 columns
        )
    SELECT
        S.COLUMN_01
        , S.COLUMN_02
        --etc., about 100 columns
    FROM
        [MYSCHEMA].[SOURCE_TABLE] AS S WITH(TABLOCK)
    WHERE
        S.TX_ID >= 1
        AND S.TX_ID < 25001
    OPTION (MAXDOP 4)
Run Code Online (Sandbox Code Playgroud)

此过程将继续加载10,000,000行。每次迭代仅检索接下来的25,000行。SELECT对[MY_SCHEMA]。[SOURCE_TABLE]上的覆盖索引执行查找。查询计划显示对BIG_MEMORY_TABLE 的序列化插入。每组25,000行大约需要1400毫秒。

如果我对托管在5-SSD条带上的基于磁盘的表执行此操作(每个磁盘5,000 IOPS,吞吐量为200MB /秒),则插入过程的速度要快得多,平均约为700ms。在基于磁盘的情况下,查询对[MY_SCHEMA]。[WIDE_DISK_TABLE] 执行并行插入。注意[MYSCHEMA]上的TABLOCK提示。[WIDE_DISK_TABLE]。

    --Insert to Disk-Based Table 
    INSERT INTO
        WIDE_DISK_TABLE WITH(TABLOCK)
        (
        TX_ID
        , COLUMN_01
        , COLUMN_02
        --etc., about 100 columns
        )
    SELECT
        S.COLUMN_01
        , S.COLUMN_02
        --etc., about 100 columns
    FROM
        [MYSCHEMA].[SOURCE_TABLE] AS S WITH(TABLOCK)
    WHERE
        S.TX_ID >= 1
        AND S.TX_ID < 25001
    OPTION (MAXDOP 4)
Run Code Online (Sandbox Code Playgroud)

当然,基于磁盘的表没有索引,并且TABLOCK提示启用了并行插入,但是我希望从INSERT到RAM的方式更多。

有任何想法吗?

谢谢!

这是对在3种模式下运行的100个批次的比较:基于磁盘的,创建延迟索引的索引,基于磁盘的,带有索引的索引和内存优化的,带有索引的索引(在内存优化的表上至少需要一个索引)。

100批次,每25,000行

Pit*_*DBA 7

更新

经过大量测试和研究,我认为这可以归结为并行性。目前,直到SP1 CU7(包括SP1 CU7)为止的SQL Server 2016不支持并行插入到内存优化表。这使得对内存优化表的所有INSERT语句都是单线程的。

这是Niko Neugebauer关于此问题的有见地的文章: Niko Neugebauer-Hekaton中的并行性(In-Memory OLTP)

这使得它对ETL / ELT摄取的用处大大减少。但是,对于OLTP DML(尤其是通过本机编译的存储过程)以及在BI查询中聚合数据的出色表现而言,这是非常令人惊讶的。对于摄取,只要采取正确的步骤以确保INSERT可以并行运行,几乎就不可能击败没有索引的基于SSD的堆。

即使数据库处于完全恢复模式,对基于磁盘的堆的并行INSERT也会优于对内存优化表的INSERT。如果在INSERT之后将可比较的索引添加到基于磁盘的表中,则这仍然保持正确。