MySQL:表中的批量更新

时间:2016-02-05 16:39:36

标签: mysql sql stored-procedures sql-update updates

我正在使用MySQL 5.6,我遇到了这个问题。 我正在尝试改善此案例的批量更新策略。

我有一个名为 reserved_ids 的表,由外部公司提供,用于为其发票分配唯一ID。没有其他方法可以做到这一点;我不能使用auto_increment字段或模拟序列。

我有这个PL伪代码来完成这个任务:

    START TRANSACTION;

OPEN invoice_cursor;

read_loop: LOOP
    FETCH invoice_cursor INTO internalID;
    IF done THEN
        LEAVE read_loop;
    END IF;


    SELECT MIN(SECUENCIAL)
    INTO v_secuencial
    FROM RESERVED_IDS
    WHERE COUNTRY_CODE = p_country_id AND INVOICE_TYPE = p_invoice_type;

    DELETE FROM RESERVED_IDS WHERE SECUENCIAL = v_secuencial;

    UPDATE MY_INVOICE SET RESERVED_ID = v_secuencial WHERE INVOICE_ID = internalID;


END LOOP read_loop;

CLOSE invoice_cursor;

COMMIT;

所以,需要一个 - 删除 - 分配,然后接下来 - 删除 - 分配...等等。

这很有效,但速度非常慢。 我不知道是否有任何方法可以更快地完成这项任务。 我正在寻找类似 INSERT INTO SELECT ... 的东西,但是使用UPDATE语句,可以直接分配1000或2000个ID,而不是逐个分配。

请,任何建议对我都很有帮助。 非常感谢。

编辑1 :我添加了 WHERE 子句详细信息,因为它是由用户@vmachan请求的。在 UPDATE ... INVOICE 子句中,我没有按其他条件进行过滤,因为我有直接和索引的发票ID,我想要更新。感谢

1 个答案:

答案 0 :(得分:0)

最后,我有这个解决方案。它比我最初的方法快得多。

UPDATE查询

set @a=0;
set @b=0;


UPDATE MY_INVOICE
INNER JOIN
(
    select 
        F.invoice_id,
        I.secuencial as RESERVED_ID, 
        CONCAT_WS(/* format your final invoice ID */) AS FINAL_MY_INVOICE_NUMBER
    FROM
    (
    select if(@a, @a:=@a+1, @a:=1) as current_row, internal_id
    from MY_INVOICE
    where reserved_id is null
    order by internal_id asc
    limit 2000
    ) F
    INNER JOIN
    (
    SELECT if(@b, @b:=@b+1, @b:=1) as current_row, secuencial
    from reserved_ids
    order by secuencial asc
    limit 2000
    ) I USING (CURRENT_ROW)
) TEMP MY_INVOICE.internal_id=TEMP.INTERNAL_ID
SET MY_INVOICE.RESERVED_ID = TEMP.RESERVED_ID, MY_INVOICE.FINAL_MY_INVOICE_NUMBER=TEMP.FINAL_MY_INVOICE_NUMBER

因此,对于自动生成和相关的secuencial数字@a和@b,我们可以加入两个不同的相关表,如MY_INVOICE和RESERVED_IDs。

如果您想查看此解决方案,请按照以下步骤执行此棘手的更新:

  • 以隔离的方式执行@a然后执行第一个内部选择:select if(@a, @a:=@a+1, ...
  • 执行@b,然后以隔离方式执行第二个内部选择:select if(@b, @b:=@b+1, ...
  • 执行@ a,@ b和构建TEMP辅助表的大选择:select F.invoice_id, ...
  • 执行UPDATE
  • 最后,从RESERVED_ID表中删除已分配的ID。

分配时间急剧减少。我的初步解决方案是一个接一个;有了这个,你可以在一个单独的(好的,有点棘手的)更新中分配2000(或更多)。

希望这有帮助。