當我從不同的數據源(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
嗯......在你的第一個問題之後,你去一個與_掙扎的另一件事。這是兩個不同的問題。 –