当我从不同的数据源(Json文件,其他数据库和REST API)导入它们时,我需要对各种数据进行重复数据删除,首先将它们加载到一个表中,该表定义它们的类型并将数据存储为Json,稍后当我运行批处理时,我可以查找类型并将数据插入到合适的表中。导入行的数量是不同的(每种类型都有不同的表格/表格),但总是超过100万个(如果我使用VARCHAR(MAX)
将它们以Json格式放置在单个表格中,那么这些数据总共会达到10G以上)。在SQL Server中执行批量插入忽略并返回id的最佳方法是什么?
正如我所说,我需要处理重复,所以我尝试定义唯一索引的目标表,并启用Ignore Duplicate Keys
,这“仅仅”当我插入现有数据提出了警告。问题是,这只适用于少数情况。大多数情况下,我需要使用5+ varchar(255)
字段,并且由于限制(900字节,src),我无法将它们添加到唯一索引。
我在挣扎的另一件事是在批量插入期间,我需要插入关系数据,这意味着一个表将有外键到另一个表。所以首先我需要处理依赖关系,并且在获得插入的Ids后,使用那些我可以插入数据的Ids。就像一个产品有一个制造商,所以我首先插入当前批次中的所有制造商名称,然后使用这些Ids我可以插入产品。
我想需要在查询返回的ID,做重复数据删除的结果来实现:
- 将同时运行,通过8-16螺纹
- 应该返回插入标识
- 应该只插入数据如果它之前没有被另一个线程插入(或根本没有插入)
首先,我试图通过使存储过程如下所示来处理这个问题:
- 尽量选择数据,如果找到,返回的Id
- 如果没有找到,重新开始交易
- 检查,如果它已经得到了由另一个线程插入。
- 如果不是,插入并返回新的ID。
代码示例这个.:
CREATE PROCEDURE [dbo].usp_insert_pdproductdetails
@GDDataSourceVersionId INT,
@ManufacturerNameId BIGINT,
@ManufacturerReference NVARCHAR(255),
@PropertiesJson NVARCHAR(MAX),
@OriginalContentPage NVARCHAR(MAX),
@NewId BIGINT OUT
AS
BEGIN
SET NOCOUNT ON;
SELECT @NewId = [Id] FROM PDProductDetails
WHERE GDDataSourceVersionId = @GDDataSourceVersionId AND
ManufacturerId = @ManufacturerNameId AND
ManufacturerReference = @ManufacturerReference;
IF @NewId IS NULL
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
SELECT @NewId = [Id] FROM PDProductDetails
WHERE GDDataSourceVersionId = @GDDataSourceVersionId AND
ManufacturerId = @ManufacturerNameId AND
ManufacturerReference = @ManufacturerReference;
IF @NewId IS NULL
BEGIN
INSERT INTO PDProductDetails (GDDataSourceVersionId, ManufacturerId, ManufacturerReference, PropertiesJson, OriginalContentPage)
VALUES(@GDDataSourceVersionId, @ManufacturerNameId, @ManufacturerReference, @PropertiesJson, @OriginalContentPage);
SELECT @NewId = SCOPE_IDENTITY();
END
COMMIT TRANSACTION
END
SELECT @NewId;
END
GO
的多个线程会调用这个并插入产品的详细信息。但是,使用这个我真的很快僵死了。我改了不同的方法,使用合并:
CREATE PROCEDURE [dbo].usp_insert_pdproductdetails
@GDDataSourceVersionId INT,
@ManufacturerNameId BIGINT,
@ManufacturerReference NVARCHAR(255),
@PropertiesJson NVARCHAR(MAX),
@OriginalContentPage NVARCHAR(MAX),
@NewId BIGINT OUT
AS
BEGIN
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
MERGE
INTO [dbo].[PDProductDetails] T
USING (SELECT @GDDataSourceVersionId, @ManufacturerNameId, @ManufacturerReference, @PropertiesJson, @OriginalContentPage)
AS Source (GDDataSourceVersionId, ManufacturerNameId, ManufacturerReference, PropertiesJson, OriginalContentPage)
ON T.GDDataSourceVersionId = Source.GDDataSourceVersionId AND
T.ManufacturerId = Source.ManufacturerNameId AND
T.ManufacturerReference = Source.ManufacturerReference
WHEN NOT MATCHED THEN
INSERT (GDDataSourceVersionId, ManufacturerId, ManufacturerReference, PropertiesJson, OriginalContentPage)
VALUES(Source.GDDataSourceVersionId, Source.ManufacturerNameId,
Source.ManufacturerReference, Source.PropertiesJson, Source.OriginalContentPage);
COMMIT TRANSACTION;
SELECT @NewId = [Id] FROM PDProductDetails (NOLOCK)
WHERE GDDataSourceVersionId = @GDDataSourceVersionId AND
ManufacturerId = @ManufacturerNameId AND
ManufacturerReference = @ManufacturerReference;
SELECT @NewId;
END
GO
这总是合并行,后来选择。它仍然陷入僵局,并不像其他人那么快,但仍然如此。
如何才能实现插入忽略并返回插入的id功能,这不会在并发环境中发生死锁?
请无效询问多个不同的问题。这是目前太宽泛的海事组织。海事组织你应该分开你有两个问题。 –
@TT。我认为这是一个单一的问题。问我怎样才能以并发方式插入忽略,同时还返回Ids。 – appl3r
嗯......在你的第一个问题之后,你去一个与_挣扎的另一件事。这是两个不同的问题。 –