我正在开展一项非常复杂的工作,我确实需要你的建议。 我需要将数据从一个表复制到另一个表,我知道对于这种方法,有很多解决方案,如
INSERT INTO newTable
SELECT * FROM oldTable
INSERT INTO newTable (col1, col2, col3)
SELECT column1, column2, column3
FROM oldTable
也可以使用SQL Cursor
,并且确实存在更多变体。
但让我总结一下这个问题:
我有一个包含大约的CSV文件。 150万条记录。每条记录目前有6个正在导入的字段。
现在,要将CSV文件中的数据插入SQL服务器,我将C#与实体框架结合使用。
为了提高性能,我会将所有这些记录插入临时表中。 这是临时表的模式:
CREATE TABLE [dbo].[TEMP_GENERIC_ARTICLE](
[Id] [int] IDENTITY(1,1) NOT NULL,
[GlnCode] [nvarchar](100) NULL,
[Description] [nvarchar](max) NULL,
[VendorId] [nvarchar](100) NULL,
[VendorName] [nvarchar](100) NULL,
[ItemNumber] [nvarchar](100) NULL,
[ItemUOM] [nvarchar](max) NULL,
[DateCreatedInternal] [datetime] NOT NULL,
[DateUpdatedInternal] [datetime] NOT NULL,
CONSTRAINT [PK_dbo.TEMP_GENERIC_ARTICLE] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
然后我有一个另一个应用程序将使用的表,称为T_GENERIC_ARTICLE
,其架构是:
CREATE TABLE [dbo].[T_GENERIC_ARTICLE](
[GlnCode] [nvarchar](100) NOT NULL,
[Description] [nvarchar](max) NULL,
[VendorId] [nvarchar](100) NOT NULL,
[VendorName] [nvarchar](100) NULL,
[ItemNumber] [nvarchar](100) NOT NULL,
[ItemUOM] [nvarchar](128) NOT NULL,
CONSTRAINT [PK_dbo.T_GENERIC_ARTICLE] PRIMARY KEY CLUSTERED
(
[GlnCode] ASC,
[VendorId] ASC,
[ItemNumber] ASC,
[ItemUOM] ASC
)
因此,真实表格不再具有“ID”字段,并且主键上有4列数据库。
现在,我想做什么:
只要数据存储在Temp
表中,或者每1000条记录存储一次,我就需要运行一个SQL存储过程,它将数据从temp
表复制到{ {1}}表。
复制后,我需要检查该主键是否已存在的记录。如果是这种情况,那么我想更新记录,否则我想插入一条新记录。
完成复制后,我想删除destination
表中的所有记录。
如果能够以尽可能快的速度将记录从temp
转移到temp
表,那么这么大的数据集(150万条记录)的最佳工作方法是什么?
我从未使用过如此庞大的数据集,所以我真的需要一些建议。
亲切的问候
答案 0 :(得分:1)
使用MERGE
将数据从登台表复制到主表,处理1.5米行应该没有问题:
MERGE [dbo].[T_GENERIC_ARTICLE] AS t
USING [TEMP_GENERIC_ARTICLE] AS s
ON s.GlnCode = t.GlnCode
AND s.VendorId = t.VendorId
AND s.ItemNumber = t.ItemNumber
AND s.ItemUOM = t.ItemUOM
WHEN MATCHED THEN UPDATE
SET Description = s.Description,
VendorName = s.VendorName
WHEN NOT MATCHED THEN
INSERT (GlnCode, Description, VendorId, VendorName, ItemNumber, ItemUOM)
VALUES (s.GlnCode, s.Description, s.VendorId, s.VendorName, s.ItemNumber, s.ItemUOM);
SSIS适用于插入,但它不能很好地处理upsert,因为OLEDB命令任务操作RBAR,因此插入登台表并使用MERGE比尝试upsert更有效直接到主表。
修改强>
回答评论中的问题:
在插入每条记录之前进行检查吗?还是仅在第一次进行检查?我的意思是,如果merge命令首先插入一条记录,对于下面的记录,它会检查它是否再次存在于目标表中(因为从上一个合并语句中添加了一条新记录)?
它首先进行检查,但是如果源表中有两个匹配的行,则MERGE将失败并显示错误消息
MERGE语句尝试多次更新或删除同一行。当目标行与多个源行匹配时会发生这种情况。 MERGE语句不能多次更新/删除目标表的同一行。优化ON子句以确保目标行最多匹配一个源行,或使用GROUP BY子句对源行进行分组。
如果临时表中有重复的行,则需要在执行合并之前对它们进行重复处理,因此,如果您只想要临时表中的最新记录,那么可以使用NOT EXISTS
exlcude记录相同键的新记录:
WITH LatestTempGenericArticle AS
(
SELECT GlnCode, Description, VendorId, VendorName, ItemNumber, ItemUOM
FROM dbo.[TEMP_GENERIC_ARTICLE] AS t
WHERE NOT EXISTS
( SELECT 1
FROM dbo.[TEMP_GENERIC_ARTICLE] AS t2
WHERE t2.GlnCode = t.GlnCode
AND t2.VendorId = t.VendorId
AND t2.ItemNumber = t.ItemNumber
AND t2.ItemUOM = t.ItemUOM
AND t2.DateCreatedInternal > t.DateCreatedInternal
)
)
MERGE [dbo].[T_GENERIC_ARTICLE] AS t
USING LatestTempGenericArticle AS s
ON s.GlnCode = t.GlnCode
AND s.VendorId = t.VendorId
AND s.ItemNumber = t.ItemNumber
AND s.ItemUOM = t.ItemUOM
WHEN MATCHED THEN UPDATE
SET Description = s.Description,
VendorName = s.VendorName
WHEN NOT MATCHED THEN
INSERT (GlnCode, Description, VendorId, VendorName, ItemNumber, ItemUOM)
VALUES (s.GlnCode, s.Description, s.VendorId, s.VendorName, s.ItemNumber, s.ItemUOM);