我正在使用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,我想要更新。感谢
答案 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。
如果您想查看此解决方案,请按照以下步骤执行此棘手的更新:
select if(@a, @a:=@a+1, ...
select if(@b, @b:=@b+1, ...
select F.invoice_id, ...
分配时间急剧减少。我的初步解决方案是一个接一个;有了这个,你可以在一个单独的(好的,有点棘手的)更新中分配2000(或更多)。
希望这有帮助。