0

我在处理更新和在 MySQL 数据库中插入数百万行时遇到了一些问题。我需要在表 A 中标记 5000 万行,将标记的 5000 万行中的一些数据插入表 B,然后再次更新表 A 中相同的 5000 万行。表 A 中有大约 1.3 亿行,表 B 中有 8000 万行。

这需要在实时服务器上进行,而不会拒绝访问来自网站的其他查询。问题是当这个存储过程运行时,来自网站的其他查询最终被锁定并且 HTTP 请求超时。

以下是 SP 的要点,为了便于说明而进行了一些简化:

CREATE DEFINER=`user`@`localhost` PROCEDURE `MyProcedure`(  
  totalLimit  int
)
BEGIN
  SET @totalLimit = totalLimit; 
  /* Prepare new rows to be issued */
  PREPARE STMT FROM 'UPDATE tableA SET `status` = "Being-Issued" WHERE `status` = "Available" LIMIT ?';
  EXECUTE STMT USING @totalLimit;
  /* Insert new rows for usage into tableB */
  INSERT INTO tableB (/* my fields */)
    SELECT /* some values from TableA */ 
    FROM tableA
    WHERE `status` = "Being-Issued";
  /* Set rows as being issued */
  UPDATE tableB SET `status` = 'Issued' WHERE `status` = 'Being-Issued';
END$$

DELIMITER ;
4

2 回答 2

0

无论您在做什么,三次处理 50M 行都会很慢。

确保您的更新影响较小的、不相交的集合。并一个一个地执行它们,而不是在同一事务中执行它们中的每一个。

如果您已经这样做并且 MySQL 行为不端,请尝试对您的代码稍作调整:

create a temporary table

begin

insert into tmp_table
select your stuff
limit ?
for update

do your update on A using tmp_table

commit

begin
do your insert on B using tmp_table
do your update on A using tmp_table
commit

这应该使锁定保持最短时间。

于 2011-05-25T16:35:41.457 回答
0

那这个呢?它基本上在循环中调用原始存储过程,直到达到所需的总量,并且在调用之间有一个休眠期(如 2 秒)以允许处理其他查询。

increment是一次要做的数量(在这种情况下使用 10,000)
totalLimit是要处理
sleepSec的总量是呼叫之间的休息时间

BEGIN
SET @x = 0;
REPEAT
    SELECT SLEEP(sleepSec);
    SET @x = @x + increment;
    CALL OriginalProcedure( increment );

    UNTIL @x >= totalLimit
END REPEAT;
END$$

显然,它可以使用一些数学来确保增量不会超过总限制,如果它不是均匀可分的,但它似乎工作(通过工作我的意思是允许其他查询仍然从网络请求处理),并且似乎整体上也更快。

这里有什么见解吗?这是一个好主意吗?馊主意?

于 2011-05-25T20:01:29.593 回答