我有两个表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"
答案 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的记录,依此类推... 希望对您有帮助。