T-SQL中的批量更新

时间:2016-06-30 11:00:02

标签: sql sql-server tsql batch-processing

我使用以下脚本以小批量删除数据库中的条目:

SET @r = 1;
WHILE @r > 0
BEGIN 
  DELETE TOP (100000)
    [doc].[Document]
    WHERE Id IN (SELECT d.Id FROM @documentIds d); 
  SET @r = @@ROWCOUNT;
END

如何以相同的方式更新表格?我在LIMIT中没有OFFSETT-SQL。我也在考虑表现方面。

3 个答案:

答案 0 :(得分:3)

您可以从临时表更新,然后删除(或使该表中的行)无效。像这样:

SET @r = 1;
WHILE @r > 0
BEGIN 
    UPDATE d
        SET col = dd.col
        FROM doc.Document d JOIN
             (SELECT TOP 10000 FROM @documents dd ORDER BY id) dd
             ON d.id = dd.id;

    DELETE d TOP 10000 FROM (SELECT TOP 10000 @documents ORDER BY id) d;

    SET @r = @@ROWCOUNT;
END;

答案 1 :(得分:1)

试试这个,使用开始和结束值并批量递增

DECLARE @Batch  INT
        ,@StartId BIGINT
        ,@EndId BIGINT
        ,@r     INT

SELECT  @Batch  = 10000
        ,@StartId = 1
        ,@EndId = 0
        ,@r     = 1

WHILE @r > 0
BEGIN 
    SET @StartId = @EndId + 1
    SET @EndId = @EndId + @Batch

    UPDATE d
        SET col = dd.col
        FROM doc.Document d 
        INNER JOIN @documents dd ON d.id = dd.id
            AND dd.id BETWEEN @StartId AND @EndId

    SET @r = @@ROWCOUNT

END

上述方法仅在您按顺序执行时才起作用,否则使用此方法预先生成批次并使用它,这将确保每次10000记录更新。

DECLARE @Batch  INT
        ,@StartId BIGINT
        ,@EndId BIGINT
        ,@Cnt INT
        ,@TotalIds INT

DECLARE @Docs TABLE 
(
        StartId BIGINT, 
        EndId BIGINT, 
        BatchID INT
)

SELECT  @Batch  = 10000
        ,@StartId = 1
        ,@EndId = 0
        ,@Cnt = 1
        ,@TotalIds = 0

;WITH CTE_Docs AS
(   SELECT TOP (100) PERCENT id, ROW_NUMBER() OVER (ORDER BY id) as RowID   -- Give seq numbers to each row
    FROM @documentIds d 
)       
-- create batches and batch start and end point
INSERT INTO @Docs(StartId, EndId, BatchId ) 
SELECT  MIN(id) StartID, 
        MAX(id) EndID, 
        (RowID/@Batch)+1 AS BatchID             
FROM CTE_Docs 
GROUP BY RowID/@Batch
ORDER BY BatchID

-- get counter to loop through
SELECT @TotalIds = MAX(BatchID)
FROM @Docs

WHILE @Cnt <= @TotalIds BEGIN   

    SELECT  @StartID    = StartID,
            @EndID      = EndID
    FROM @Docs
    WHERE BatchID = @Cnt

    UPDATE d
        SET col = dd.col
        FROM doc.Document d 
        INNER JOIN @documents dd ON d.id = dd.id
            AND dd.id BETWEEN @StartId AND @EndId

    SET @Cnt = @Cnt + 1

END

希望这有帮助。

答案 2 :(得分:0)

这样做。这将每300毫秒删除1000条记录。但我在这里做的好事是,我发布了交易,并允许另一个交易完成。因为可能有另一个CRUD声明。此查询不会阻止事务,我使用它来删除/更新生产服务器上的数百万条记录。因为我看到的答案仍会阻止其他事务,因为该进程仍会附加到一个会导致高CPU和DISK IO的事务。此外,我将DEADLOCK PRIORITY设置为低,因此另一个事务具有更高的重要性。确实需要更长的时间。但这对于服务器成本而言是SAFER,并且没有阻止的事务。

SET DEADLOCK_PRIORITY -10

DECLARE @r = 1;

WHILE @r > 0 > 0
BEGIN 
    DELETE TOP (1000)
    [doc].[Document]
    WHERE Id IN (SELECT d.Id FROM @documentIds d); 
    SET @r = @@ROWCOUNT;

    WAITFOR DELAY '00:00:00.300'

END