缓慢更新,无法解决原因

时间:2017-08-26 22:21:26

标签: mysql database join

我有一个缓慢的UPDATE语句,无法解决原因

CREATE TEMPORARY TABLE ttShifts
(ShiftId int NOT NULL, ttdtAdded datetime not null, ttdtBookingStart DATETIME NOT NULL, ttHoursNeeded int not null, szHidden varchar(255),
 PRIMARY KEY (ShiftID))
 AS
 (select shiftId, dtAdded as ttdtAdded, dtBookingStart as ttdtBookingStart, HoursNeeded as ttHoursNeeded from shifts where shifts.lStatus=0);

 update ttShifts set szHidden='x' where szHidden is NULL and ShiftId in (select shiftid from shifts,practices where shifts.PracticeId=practices.PracticeId and shifts.iBranch = practices.iBranch and practices.Healthboard not in (select Locname from userlocationprefs where iUser=82 and Level=0 and fAcceptWork=true))

166 rows affected. (Query took 0.2899 seconds.)    

EXPLAIN:

  1 PRIMARY ttShifts    index       PRIMARY 4       297 Using where 
  2 DEPENDENT SUBQUERY  shifts  eq_ref  PRIMARY PRIMARY 4   func    1       
  2 DEPENDENT SUBQUERY  practices   ALL PRIMARY             636 Using where; Using join buffer (flat, BNL join) 
  3 MATERIALIZED    userlocationprefs   ref PRIMARY PRIMARY 8   const,const 3   Using where 

好的,让我们尝试将其切换为使用连接来消除从属子查询

update ttShifts join shifts on (ttShifts.ShiftID=shifts.shiftId) join practices on (shifts.practiceId=practices.PracticeId and shifts.iBranch=practices.iBranch) set szHidden='x' where szHidden is NULL and practices.Healthboard not in (select Locname from userlocationprefs where iUser=82 and Level=0 and fAcceptWork=true);

166 rows affected. (Query took 0.4009 seconds.)

是的,所以更长

说明:

1   PRIMARY ttShifts    ALL PRIMARY             297 Using where 
1   PRIMARY shifts  eq_ref  PRIMARY PRIMARY 4   ttShifts.shiftId    1       
1   PRIMARY practices   ALL                 636 Using where 
2   MATERIALIZED    userlocationprefs   ref PRIMARY PRIMARY 8   const,const 3   Using where 

好的,所以它必须是MATERIALIZED位,它由于某种原因没有效率,让我们尝试将它交换为直接的相等检查,就像测试一样。

update ttShifts join shifts on (ttShifts.ShiftID=shifts.shiftId) join practices on (shifts.practiceId=practices.PracticeId and shifts.iBranch=practices.iBranch) set szHidden='x' where szHidden is NULL and practices.Healthboard!='X'

0.3493秒。

好的,不是那么。

如果我取消更新并将其设为选择...

select * from ttShifts join shifts on (ttShifts.ShiftID=shifts.shiftId) join practices on (shifts.practiceId=practices.PracticeId and shifts.iBranch=practices.iBranch) where szHidden is NULL and practices.Healthboard not in (select Locname from userlocationprefs where iUser=82 and Level=0 and fAcceptWork=true)

(166 rows, Query took 0.0159 seconds.)

那么为什么UPDATE如此血腥缓慢,我该怎么做才能加快速度呢?

2 个答案:

答案 0 :(得分:0)

您的第一个EXPLAIN输出告诉我们它需要处理297 * 1 * 636 * 3行= 566,676行。所以是的,它需要一点时间来处理。它类似于第二个EXPLAIN输出。

如果我是你,我会尝试关注标记为ALL的条目,因为它代表了表扫描操作。

此外,IN最适合使用常量值列表而非子查询,因为它们会导致索引无效。如果可能,尝试使用常量值删除子查询。

第二个EXPLAIN更糟糕,因为有两个没有索引的表扫描可供使用。

第三次更新没有EXPLAIN输出,但我认为因为您使用低基数(not null)和healthBoard !='x'的列作为过滤条件WHERE子句,因此要处理的行数仍然很高。

您的上一个查询尝试比较SELECT与UPDATE的速度。好吧,UPDATE更昂贵,因为它必须搜索匹配的行,写入值,写入索引。

从我看到的,你的大多数问题是由于低基数列被用作过滤标准。

答案 1 :(得分:0)

对于遇到此问题的其他任何人来说,似乎问题在于优化器如何使用update vs select处理IN。我重构了一些内容,因此用户查看首选项是在一个单独的表testuserchosenpractices中设置的,然后我可以加入它。

我无法解释UPDATE和SELECT之间的速度差异(因为SELECT是完全可以容忍的)但是替换UPDATE比原来的SELECT更快!

更新(选择1)为虚拟,ttShifts设置szHidden =' x'其中szHidden是NULL和ShiftId(从shift中选择shiftid join实践(shifting.PracticeId = practices.PracticeId和shifting.iBranch = practices.iBranch)连接testuserchosenpractices(shifting.practiceid = testuserchosenpractices.practiceid和shifting.ibranch = testuserchosenpractices。 ibranch和testuserchosenpractices.iUser = 82)和szReason!='')

受影响的166行。 (查询耗时0.0066秒。)