如何在MySql中更新数百万条记录?

时间:2018-08-19 11:38:36

标签: mysql indexing sql-update

我有两个表tableA和tableB。 tableA具有200万条记录,而tableB具有1000万条记录。 tableA具有三十多列,而tableB只有两列。我需要通过联接两个表来更新tableB中tableA中的列。

UPDATE tableA a 
INNER JOIN tableB b  ON a.colA=b.colA
 SET a.colB= b.colB 
两个表中的

colA已被索引。

现在,当我执行查询时,它需要几个小时。老实说,我从来没有看到它完成,我等待的最大时间是5个小时。他们有什么办法在20-30分钟内完成此查询。我应该采取什么方法。

对SQL查询的解释

"id" "_type" "table" "type" "possible_" "key" "key_len"   "ref"   "rows" "Extra"
"1" "SIMPLE" "a"     "ALL"  "INDX_DESC" \N    \N          \N   "2392270"  "Using where"
"1" "SIMPLE" "b"     "ref"  "indx_desc" "indx_desc" "133" "cis.a.desc" "1"  "Using where"

4 个答案:

答案 0 :(得分:0)

您的UPDATE操作正在对一个大表的一千万行执行一次事务。 (DBMS保留足够的数据,如果由于某种原因未完成查询,则可以回滚整个UPDATE查询。)对于您的服务器而言,这种大小的事务处理速度很慢。

处理整个表时,该操作无法像使用具有高度选择性的WHERE子句那样使用索引。

一些尝试:

1)除非行需要,否则不要更新。跳过已经具有正确值的行。如果大多数行已经具有正确的值,这将使您的更新更快。

    UPDATE tableA a 
INNER JOIN tableB b  ON a.colA=b.colA
       SET a.colB = b.colB
     WHERE a.colB <> b.colB 

2)以几千行的块为单位进行更新,然后重复更新操作,直到整个表被更新为止。我猜tableA包含一个id列。您可以使用它来组织要更新的行块。

    UPDATE tableA a 
INNER JOIN tableB b  ON a.colA=b.colA
       SET a.colB = b.colB
     WHERE a.id IN  (
             SELECT a.id
               FROM tableA
              INNER JOIN tableB ON a.colA = b.colA
              WHERE a.colB <> b.colB
              LIMIT 5000
      ) 

子查询查找尚未更新的5000行的id值,然后UPDATE查询更新它们。重复此查询,直到不更改任何行,然后完成。这使事情变得更快,因为服务器只能处理较小的事务。

3)完全不执行更新。相反,无论何时需要检索colB值,只需在选择查询中加入tableB。

答案 1 :(得分:0)

进行块处理是正确的方法。但是,PRIMARY KEY的{​​{1}}上的块。

我建议一次只显示1000行。

按照给出的提示here

您是说tableA的PK是varchar吗?没问题。请参阅该链接中的第二种代码。不管tableA(PK)的数据类型如何,它都使用ORDER BY id LIMIT 1000,1查找下一个块的结尾。

答案 2 :(得分:0)

为了更新单个MySQL表的大约7000万条记录,我编写了一个存储过程以5000个块的形式更新该表。大约花了3个小时才能完成。

DELIMITER $$
DROP PROCEDURE IF EXISTS update_multiple_example_proc$$
CREATE PROCEDURE update_multiple_example_proc()
BEGIN
DECLARE x  bigint;

SET x = 1;

WHILE x  <= <MAX_PRIMARY_KEY_TO_REACH> DO
UPDATE tableA A
   JOIN tableB B
   ON A.col1 = B.col1
SET A.col2_to_be_updated = B.col2_to_be_updated where A.id between x and x+5000 ;
SET  x = x + 5000;
END WHILE;

END$$
DELIMITER ;

答案 3 :(得分:-1)

嗨,我不确定,但是您可以按计划执行工作。 流程:在表tableA中,您需要再添加一个字段(例如)is_update,将其默认值设置为0,每分钟设置一次cron作业。当cron工作时:例如,它第一次选择具有is_update字段0值的10000条记录并更新记录并设置is_update is1,第二次选择其下一个10000具有is_update 0的记录,依此类推... 希望对您有帮助。