这是一种使用带有已解析 CSV 数据的暂存表的 MERGE 技术。或者,您可以使用表值参数而不是临时表源。
关于您的碎片问题,这主要取决于在现有目标表日期范围内插入了多少新行。如果没有该范围内的新行,则碎片是微不足道的(低于 3%,如下面的脚本所示。如果碎片成为问题,您始终可以在 ETL 之后执行索引 REBUILD 或 REORGANIZE。
CREATE TABLE dbo.Test(
TestDateTime datetime2(0) NOT NULL
CONSTRAINT PK_Test PRIMARY KEY
, TestData int NOT NULL
);
CREATE TABLE dbo.TestStaging(
TestDateTime datetime2(0) NOT NULL
CONSTRAINT PK_TestStaging PRIMARY KEY
, TestData int NOT NULL
);
GO
--load 10 days into main table (61710 per day)
WITH
t4 AS (SELECT n FROM (VALUES(0),(0),(0),(0)) t(n))
,t256 AS (SELECT 0 AS n FROM t4 AS a CROSS JOIN t4 AS b CROSS JOIN t4 AS c CROSS JOIN t4 AS d)
,t256K AS (SELECT ROW_NUMBER() OVER (ORDER BY (a.n)) - 1 AS num FROM t256 AS a CROSS JOIN t256 AS b CROSS JOIN t4 AS c)
INSERT INTO dbo.Test WITH(TABLOCKX) (TestDateTime, TestData)
SELECT DATEADD(second, num*7, CAST('2015-07-01T00:00:00' AS datetime2(0))), num
FROM t256K
WHERE num <= 123420;
GO
--load 4 most recent days with new values plus 1 new day into staging table
WITH
t4 AS (SELECT n FROM (VALUES(0),(0),(0),(0)) t(n))
,t256 AS (SELECT 0 AS n FROM t4 AS a CROSS JOIN t4 AS b CROSS JOIN t4 AS c CROSS JOIN t4 AS d)
,t256K AS (SELECT ROW_NUMBER() OVER (ORDER BY (a.n)) - 1 AS num FROM t256 AS a CROSS JOIN t256 AS b CROSS JOIN t4 AS c)
INSERT INTO dbo.TestStaging WITH(TABLOCKX) (TestDateTime, TestData)
SELECT DATEADD(second, num*7, CAST('2015-07-07T00:00:06' AS datetime2(0))), num
FROM t256K
WHERE num <= 61710;
GO
--show fragmentation before MERGE
SELECT *
FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID(N'dbo.Test'), NULL, NULL, 'DETAILED');
GO
MERGE dbo.Test AS target
USING dbo.TestStaging AS source ON
source.TestDateTime = target.TestDateTime
WHEN MATCHED THEN
UPDATE SET TestData = source.TestData
WHEN NOT MATCHED BY target THEN
INSERT (TestDateTime, TestData) VALUES (source.TestDateTime, source.TestData);
GO
--show fragmentation after MERGE
SELECT *
FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID(N'dbo.Test'), NULL, NULL, 'DETAILED');
GO