【问题标题】:How do I speed up the batch of update queries over the table with 2 million rows?如何加快对具有 200 万行的表的批量更新查询?
【发布时间】:2020-08-12 01:19:04
【问题描述】:

我有大约 200 万个更新查询

UPDATE table1 
SET WIN = 'A-9-0-9999-00000-00000-0000' 
WHERE WIN= 'A-0-9-0000-999999-000000'

现在我有大约 200 万个更新查询,我将它们粘贴到 SQL 窗口中并立即运行,但每个系统大约需要 1 小时(我在不同的服务器上拥有相同的数据库)。

table1 本身有 200 万行。

我已经从 WIN 列中删除了 varchar 类型的索引。

如何加快速度?

更新:

为了让您知道,我有大约 200 万个更新查询,与上面的查询类似,具有不同的值。

 UPDATE table1 
    SET WIN = 'A-9-0-9999-00000-00000-0000' 
    WHERE WIN= 'A-0-9-0000-999999-000000'

.

.
.
.
.
.
.
.
.
.
.
 UPDATE table1 
    SET WIN = 'G-6-H-9999-00000-00000-0000' 
    WHERE WIN= 'A-1-9-0000-999999-000000'

我一下子就跑了。

【问题讨论】:

  • 批量更新
  • JOIN 然后@Monkeyguru 向我们展示您的实际查询。以上只是用 1 个值更新 1 行(我假设)。不是 200 万。
  • “有 200 万行具有不同的值” 是的……这就是为什么我要求您查询在两个表之间执行 JOIn 的原因;然后我们可以告诉你如何分批。
  • 删除索引也是一个非常糟糕的主意,因为这些都是单独的语句,因此需要共同扫描 200 万平方行(4 万亿)
  • 没有它,您的 200 万个 UPDATE 语句中的每一个都需要扫描整个 200 万行以找到要更新的行。但理想情况下,无论如何你都会摆脱这 200 万条语句。您应该将“旧”和“新”值批量插入临时表中,然后您可以将其用于基于集合的更新

标签: sql sql-server tsql stored-procedures sql-server-2012


【解决方案1】:

我认为您应该将更新转换为插入并分批执行。

SET XACT_ABORT ON;
SET NOCOUNT ON;

CREATE TABLE #Replaces  (
    ReplaceId INT      NOT NULL IDENTITY PRIMARY KEY,
    OldWIN    CHAR(27) NOT NULL,
    NewWIN    CHAR(27) NOT NULL,
    TargetId  INT
);

INSERT INTO #Replaces (OldWIN, NewWIN)
VALUES('A-9-0-9999-00000-00000-0000', 'A-0-9-0000-999999-000000')
-- ...
-- ...
INSERT INTO #Replaces (OldWIN, NewWIN)
VALUES('G-6-H-9999-00000-00000-0000', 'A-1-9-0000-999999-000000')

-- Scan for Id in table1 once.
UPDATE Replaces
SET TargetId = table1.Id
FROM #Replaces AS Replaces
INNER JOIN table1 ON table1.WIN = Replaces.OldWIN

DECLARE @BATCH_SIZE INT = 500;

DECLARE @batch    TABLE (
    ReplaceId INT      NOT NULL PRIMARY KEY,
    TargetId  INT      NOT NULL,
    NewWin    CHAR(27) NOT NULL
);
DECLARE @maxId    INT = 0;

WHILE 1 = 1
BEGIN
    BEGIN TRY
        INSERT INTO @batch (ReplaceId, TargetId, NewWIN)
        SELECT TOP (@BATCH_SIZE) ReplaceId, TargetId, NewWIN
        FROM #Replaces
        WHERE ReplaceId > @maxId
        ORDER BY ReplaceId;

        IF @@ROWCOUNT = 0 BREAK;

        UPDATE table1
        SET WIN = Batch.NewWin
        FROM @batch AS Batch
        INNER JOIN table1 ON table1.Id = Batch.TargetId

        SELECT @maxId = MAX(ReplaceId) FROM @batch;

        DELETE @batch;
    END TRY BEGIN CATCH
        SELECT ERROR_MESSAGE = ERROR_MESSAGE();
        BREAK;
    END CATCH
END

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-30
    • 2014-06-28
    • 2016-06-19
    • 2014-08-10
    • 2018-01-01
    • 1970-01-01
    • 2021-11-20
    相关资源
    最近更新 更多