【问题标题】:MySQL - Update with Join suddenly takes foreverMySQL - 使用 Join 更新突然需要很长时间
【发布时间】:2016-09-29 04:51:46
【问题描述】:

我有一个主表 MainTable。有大约 450 万行。 这是它的创建查询:

create table MainTable(
   status_day date DEFAULT NULL, 
   i_station_id int DEFAULT NULL, 
   i_TZ int DEFAULT NULL, 
   CID int DEFAULT NULL, 
   Calc1 double DEFAULT NULL, 
   Calc2 double DEFAULT NULL, 
   ...
   Calc80 double DEFAULT NULL, 
UNIQUE KEY uniqueindex (status_day, i_station_id, i_TZ, CID)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

我需要使用另一个 TEMP 表中的值更新几个字段。它有大约 760K 行,它是 create 语句:

create temporary table TEMP (
   status_day date DEFAULT NULL, 
   i_station_id int DEFAULT NULL, 
   i_TZ int DEFAULT NULL, 
   CID int DEFAULT NULL,, 
   Calc13 double DEFAULT NULL, 
   Calc14 double DEFAULT NULL, 
   Calc17 double DEFAULT NULL, 
   Calc24 double DEFAULT NULL, 
   Calc68 double DEFAULT NULL, 
   Calc70 double DEFAULT NULL, 
UNIQUE KEY indexxx (status_day, i_station_id, i_TZ, CID)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

出于某种原因,此更新查询:

大约需要 3 小时。那有意义吗?对我来说似乎太长了。

update MainTable as A join TEMP as B on
        (A.status_day = B.status_day and 
        A.i_station_id = B.i_station_id and 
        A.i_TZ = B.i_TZ and 
        A.CID = B.CID) 
set 
   A.Calc13 = B.Calc13, 
   A.Calc14 = B.Calc14, 
   A.Calc17 = B.Calc17, 
   A.Calc24 = B.Calc24, 
   A.Calc68 = B.Calc68, 
   A.Calc70 = B.Calc70

这是结果

Explain select 
    * 
from MainTable as a join TEMP as b on
    (a.status_day = b.status_day and 
    a.i_station_id = b.i_station_id and 
    a.i_TZ = b.i_TZ and 
    a.CID = b.CID) 




ID     select_type   table    type    possible_keys  key          key_len rows  
1      SIMPLE        b        ALL     indexxx                             692967
1      SIMPLE        a        ref     uniqueindex    uniqueindex  23      1

有什么想法吗?

谢谢? :)

更新:回答:增加服务器的内存和 CPU 立即解决了这个问题。

【问题讨论】:

  • 最好从解释计划中添加行数。您加入的字段之间是否有任何重复值,例如空字段?这可能会使您的更新找到大量匹​​配的行,并解释执行时间长。
  • 嘿:) 连接字段上没有重复项,它们是两个表上的唯一键...我在解释输出中添加了行数
  • 我曾经遇到过类似的问题,就是磁盘 I/O。正如 rhavendc 所写,3 小时对于查询来说太多了。但是您的查询似乎很好,并且行数确实没有那么高。莫非同时还有另一笔大交易在运行?如果可能,我会在另一台服务器上测试查询,如果没有,您可以制作表的副本,重建索引并使用副本测试查询以确保它与表无关。

标签: mysql performance join


【解决方案1】:

我不太清楚为什么查询需要 3 小时,这太荒谬了。也许您要加入的列有问题,但您也可以进行如下查询:

UPDATE MainTable A, TEMP B
SET
     Calc13 = B.Calc13, 
     Calc14 = B.Calc14, 
     Calc17 = B.Calc17, 
     Calc24 = B.Calc24, 
     Calc68 = B.Calc68, 
     Calc70 = B.Calc70
WHERE
     A.status_day = B.status_day
     AND A.i_station_id = B.i_station_id
     AND A.i_TZ = B.i_TZ
     AND A.CID = B.CID

【讨论】:

    【解决方案2】:

    3 小时的部分成本是构建一个巨大的“回滚”日志。

    我会围绕每次迭代更新 1000 行(或更少)进行构建。或者,更简单地说,在单个UPDATE 中更新一个TEMP.status_day 的所有行,然后转到下一个TEMP.status_day。可以使用存储过程或应用程序代码。

    如果您这样做,请务必在每个 UPDATE 之后发送 COMMIT。 (或者干脆使用autocommit=1。)

    More on chunking.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-26
      相关资源
      最近更新 更多