SQL Server 2008 R2 には 2 つのテーブルがあります。定期的に、テーブル A からテーブル B に一連のレコードを挿入する必要があります。挿入中、テーブル B は引き続き SELECT と UPDATE を実行できます。現在、テーブル A からテーブル B にコピーするために INSERT..SELECT を使用しています。
ブロッキングを引き起こさない、テーブルから別のテーブルへのより良い一括挿入ソリューションはありますか?
SQL Server 2008 R2 には 2 つのテーブルがあります。定期的に、テーブル A からテーブル B に一連のレコードを挿入する必要があります。挿入中、テーブル B は引き続き SELECT と UPDATE を実行できます。現在、テーブル A からテーブル B にコピーするために INSERT..SELECT を使用しています。
ブロッキングを引き起こさない、テーブルから別のテーブルへのより良い一括挿入ソリューションはありますか?
1 ステートメントがタイムアウトにならないように、トランザクション タイムアウトを十分に大きな値に設定します。
2 CURSOR を使用して行ごとに実行する
3 このやり方を試してみてください。行識別子 (IDENTITY など) が必要です。そのフィールドに PK または INDEX を設定するのが最適です。
SET NOCOUNT ON;
CREATE TABLE #A(
row_id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
data INT NOT NULL
);
CREATE TABLE #B(
row_id INT NOT NULL PRIMARY KEY,
data INT NOT NULL
);
-- TRUNCATE TABLE #B; -- no truncate needed since you just want to add rows, not copy the whole table
DECLARE @batch_size INT;
SET @batch_size = 10000;
DECLARE @from_row_id INT;
DECLARE @to_row_id INT;
-- You would use this to establish the first @from_row_id if you wanted to copy the whole table
-- SELECT
-- @from_row_id=ISNULL(MIN(row_id),-1)
-- FROM
-- #A AS a;
SELECT
@from_row_id=ISNULL(MAX(row_id),-1)
FROM
#B AS b;
IF @from_row_id=-1
SELECT
@from_row_id=ISNULL(MIN(row_id),-1)
FROM
#A AS a;
ELSE
SELECT
@from_row_id=ISNULL(MIN(row_id),-1)
FROM
#A AS a
WHERE
row_id>@from_row_id;
WHILE @from_row_id>=0
BEGIN
SELECT
@to_row_id=ISNULL(MAX(row_id),-1)
FROM
(
SELECT TOP(@batch_size)
row_id
FROM
#A AS a
WHERE
row_id>=@from_row_id
) AS row_ids
IF @to_row_id=-1
BEGIN
INSERT
#B
SELECT
*
FROM
#A AS a
WHERE
row_id>=@from_row_id;
BREAK;
END
ELSE
INSERT
#B
SELECT
*
FROM
#A AS a
WHERE
row_id BETWEEN @from_row_id AND @to_row_id;
SELECT
@from_row_id=ISNULL(MIN(row_id),-1)
FROM
#A AS a
WHERE
row_id>@to_row_id;
END
DROP TABLE #B;
DROP TABLE #A;
彼らの最も明白な解決策は、スタンレーが提案したように、より小さなバッチを使用することです。これが実際にオプションではない場合は、「(トランザクション レベル) スナップショット分離」を検討できます。