10

我观察到将数据插入到内存优化表中比在 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]

对于这个特定的测试,我将 10,000,000 行以 25,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)

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

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

    --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)

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

有任何想法吗?

谢谢!

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

100 批,每批 25K 行

4

1 回答 1

9

更新

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

这是 Niko Neugebauer 关于这个问题的一篇有见地的文章: Niko Neugebauer - Parallelism in Hekaton (In-Memory OLTP)

这使得它对 ETL/ELT 摄取的用处大大降低。但是,对于 OLTP DML(尤其是通过本机编译的存储过程)来说,这非常令人惊奇,并且在 BI 查询中聚合数据方面非常出色。对于摄取,几乎不可能在没有索引的情况下击败基于 SSD 的堆,只要您采取正确的步骤来确保您的 INSERT 将并行运行。

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

于 2018-02-10T15:36:56.833 回答