【问题标题】:Memory Optimized Tables - Slower INSERT than SSD内存优化表 - 插入速度比 SSD 慢
【发布时间】:2018-07-14 03:16:43
【问题描述】:

我观察到,将数据插入内存优化表比在 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 个批次的比较:基于磁盘,使用延迟索引创建,基于磁盘使用索引,以及使用索引优化内存(内存优化表至少需要一个索引)。

【问题讨论】:

  • 为什么不使用基于磁盘的索引进行测试?很容易认为这是很小的,但通常不是……工作量加倍有时是工作量的两倍。
  • 您的内存表是否使用行溢出存储?想知道是否会导致性能下降。
  • 这里的这一段看起来很相关aboutsqlserver.com/2016/09/27/…对于他们所做的具体实验“我的环境中INSERT语句的执行时间分别为153和7,722毫秒。使用行外存储,内存中OLTP需要向其他 20 个内部表添加数据,这比行内存储慢 40 倍。”
  • @MartinSmith 想法不错,但我们没有使用行外存储。它只是一堆 NVARCHAR (大部分是小的)和一些 DECIMAL。这是该表的 sys.dm_db_xtp_memory_consumers 输出的图像:imgur.com/a/Z99zy
  • @MartinSmith 这归结为并行的力量。查看我自己发布的答案和 Niko Neugebauer 的相关文章。

标签: sql-server performance query-performance memory-optimized-tables


【解决方案1】:

更新

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

以下是 Niko Neugebauer 关于此问题的一篇富有洞察力的文章: Niko Neugebauer - Parallelism in Hekaton (In-Memory OLTP)

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

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

【讨论】:

    猜你喜欢
    • 2017-11-01
    • 2011-02-25
    • 2012-07-24
    • 2021-08-30
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多