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个批次的比较:基于磁盘的,创建延迟索引的索引,基于磁盘的,带有索引的索引和内存优化的,带有索引的索引(在内存优化的表上至少需要一个索引)。
更新
经过大量测试和研究,我认为这可以归结为并行性。目前,直到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之后将可比较的索引添加到基于磁盘的表中,则这仍然保持正确。