我们在 SQL Server 2008 R2 中有 2 个表。周期性地,我们必须将一批记录从表 A 插入到表 B。在插入时,表 B 仍然能够 SELECT & UPDATE。目前,我们使用 INSERT..SELECT 从表 A 复制到表 B。但问题是在插入时,有时会导致 UPDATE 语句对表 B 超时。
有没有更好的从一个表到另一个不会导致阻塞的批量插入解决方案?
我们在 SQL Server 2008 R2 中有 2 个表。周期性地,我们必须将一批记录从表 A 插入到表 B。在插入时,表 B 仍然能够 SELECT & UPDATE。目前,我们使用 INSERT..SELECT 从表 A 复制到表 B。但问题是在插入时,有时会导致 UPDATE 语句对表 B 超时。
有没有更好的从一个表到另一个不会导致阻塞的批量插入解决方案?
他们最明显的解决方案是按照斯坦利的建议使用较小的批次。如果这真的不是一个选项,您可以探索' (事务级别)快照隔离。
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;