内存优化表 - INSERT 比 SSD 慢
Memory Optimized Tables - Slower INSERT than SSD
我观察到,将数据插入内存优化 Table 比在 5-SSD 条带集上基于磁盘 table 的等效并行插入要慢得多。
--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 为一组的方式批处理到此 table 中。对于内存优化 Table:
,该语句看起来像这样
--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 毫秒。
如果我对基于磁盘的 table 执行此操作,托管在 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)
诚然,基于磁盘的 table 没有索引,并且 TABLOCK 提示启用并行插入,但我希望从 INSERT 到 RAM 的方式更多。
有什么想法吗?
谢谢!
这里是 100 个批处理 运行 在 3 种模式下的比较:基于磁盘,使用延迟索引创建,基于磁盘并使用索引,以及使用索引优化内存(至少需要一个索引内存优化 tables).
更新
经过大量测试和研究,我相信这归结为并行性。目前,SQL Server 2016,直到并包括 SP1 CU7,不支持并行插入内存优化表。 这使得内存优化 table 的所有 INSERT 语句都是单线程的。
以下是 Niko Neugebauer 关于此问题的一篇有见地的文章:
Niko Neugebauer - Parallelism in Hekaton (In-Memory OLTP)
这使得它对 ETL/ELT 摄取的用处大打折扣。然而,对于 OLTP DML(尤其是通过本机编译的存储过程)来说,它是相当惊人的,并且在 BI 查询中聚合数据方面也很出色。对于摄取,没有索引几乎不可能击败基于 SSD 的堆,只要您采取正确的步骤以确保您的 INSERT 将 运行 并行。
即使数据库处于完全恢复模式,并行 INSERT 到基于磁盘的堆也优于 INSERT 到内存优化 table。如果在 INSERT.
之后将可比索引添加到基于磁盘的 table,这将继续保持正确。
我观察到,将数据插入内存优化 Table 比在 5-SSD 条带集上基于磁盘 table 的等效并行插入要慢得多。
--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 为一组的方式批处理到此 table 中。对于内存优化 Table:
,该语句看起来像这样 --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 毫秒。
如果我对基于磁盘的 table 执行此操作,托管在 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)
诚然,基于磁盘的 table 没有索引,并且 TABLOCK 提示启用并行插入,但我希望从 INSERT 到 RAM 的方式更多。
有什么想法吗?
谢谢!
这里是 100 个批处理 运行 在 3 种模式下的比较:基于磁盘,使用延迟索引创建,基于磁盘并使用索引,以及使用索引优化内存(至少需要一个索引内存优化 tables).
更新
经过大量测试和研究,我相信这归结为并行性。目前,SQL Server 2016,直到并包括 SP1 CU7,不支持并行插入内存优化表。 这使得内存优化 table 的所有 INSERT 语句都是单线程的。
以下是 Niko Neugebauer 关于此问题的一篇有见地的文章: Niko Neugebauer - Parallelism in Hekaton (In-Memory OLTP)
这使得它对 ETL/ELT 摄取的用处大打折扣。然而,对于 OLTP DML(尤其是通过本机编译的存储过程)来说,它是相当惊人的,并且在 BI 查询中聚合数据方面也很出色。对于摄取,没有索引几乎不可能击败基于 SSD 的堆,只要您采取正确的步骤以确保您的 INSERT 将 运行 并行。
即使数据库处于完全恢复模式,并行 INSERT 到基于磁盘的堆也优于 INSERT 到内存优化 table。如果在 INSERT.
之后将可比索引添加到基于磁盘的 table,这将继续保持正确。