【问题标题】:Why would UPDATE with JOIN queries be so much slower than SELECT with JOIN queries?为什么带有 JOIN 查询的 UPDATE 比带有 JOIN 查询的 SELECT 慢得多?
【发布时间】:2013-08-29 18:27:18
【问题描述】:

这是一场长达 19 小时的噩梦。

我有一个非常大的查询,本质上需要跨几个表连接大型数据集。进行连接后,我需要使用 select 语句中的数据更新原始表。 SELECT 语句超级快,而 UPDATE 语句超级慢。

这是选择语句。

SELECT l.col1,
       l.col2,
       l.col3,
       p.personid
FROM table1 p
LEFT JOIN table2 l ON (l.col1 = p.col1)
LEFT JOIN
  (SELECT name,
          col AS 'col2'
   FROM tbl3 f
   WHERE f.col LIKE '%-F') pcf ON (pcf.col1 = p.col1)
LEFT JOIN
  (SELECT name,
          col AS 'col3'
   FROM tbl4 f
   WHERE f.col LIKE '%-M') pcm ON (pcm.col1 = p.col1)
WHERE p.requestid = '1928'

现在,如果我采用 EXACT SAME 系列的 JOIN 并将其放入 UPDATE 上下文中,则查询将永远持续。

UPDATE table1 p
LEFT JOIN table2 l ON (l.col1 = p.col1)
LEFT JOIN
  (SELECT name,
          col AS 'col2'
   FROM tbl3 f
   WHERE f.col LIKE '%-F') pcf ON (pcf.col1 = p.col1)
LEFT JOIN
  (SELECT name,
          col AS 'col3'
   FROM tbl4 f
   WHERE f.col LIKE '%-M') pcm ON (pcm.col1 = p.col1)
SET p.col1 = l.col1,
    p.col2 = l.col2,
    p.col3 = l.col3
WHERE p.requestid = '1928'

那么...为什么 UPDATE JOIN 语句会比 SELECT JOIN 语句花费这么多时间?时间更长。而且我已经尝试过临时表,但它不起作用。

仅供参考,我正在处理包含 50k 或更多记录的表。

如果您对 EXPLAIN 结果感到好奇,这就是我 EXPLAIN 选择查询时发生的情况(尽管显然您不能使用 explain 进行更新?)

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   PRIMARY p   ALL NULL    NULL    NULL    NULL    613246  Using where
1   PRIMARY l   eq_ref  PRIMARY,name_3,name,name_2  PRIMARY 257 drilldev_db.p.lastname  1   
1   PRIMARY <derived2>  ALL NULL    NULL    NULL    NULL    23435   
1   PRIMARY <derived3>  ALL NULL    NULL    NULL    NULL    13610   
1   PRIMARY <derived4>  ALL NULL    NULL    NULL    NULL    13053   
1   PRIMARY <derived5>  ALL NULL    NULL    NULL    NULL    8273    
1   PRIMARY <derived6>  ALL NULL    NULL    NULL    NULL    11481   
1   PRIMARY <derived7>  ALL NULL    NULL    NULL    NULL    6708    
1   PRIMARY <derived8>  ALL NULL    NULL    NULL    NULL    9588    
1   PRIMARY <derived9>  ALL NULL    NULL    NULL    NULL    5494    
1   PRIMARY <derived10> ALL NULL    NULL    NULL    NULL    6981    
1   PRIMARY <derived11> ALL NULL    NULL    NULL    NULL    4107    
1   PRIMARY <derived12> ALL NULL    NULL    NULL    NULL    5973    
1   PRIMARY <derived13> ALL NULL    NULL    NULL    NULL    3851    
1   PRIMARY <derived14> ALL NULL    NULL    NULL    NULL    4935    
1   PRIMARY <derived15> ALL NULL    NULL    NULL    NULL    3574    
1   PRIMARY <derived16> ALL NULL    NULL    NULL    NULL    5793    
1   PRIMARY <derived17> ALL NULL    NULL    NULL    NULL    4706    
17  DERIVED f   ref year,gender gender  257     364263  Using where; Using temporary; Using filesort
16  DERIVED f   ref year,gender gender  257     397322  Using where; Using temporary; Using filesort
15  DERIVED f   range   year,gender year    4   NULL    54092   Using where; Using temporary; Using filesort
14  DERIVED f   range   year,gender year    4   NULL    54092   Using where; Using temporary; Using filesort
13  DERIVED f   range   year,gender year    4   NULL    62494   Using where; Using temporary; Using filesort
12  DERIVED f   range   year,gender year    4   NULL    62494   Using where; Using temporary; Using filesort
11  DERIVED f   range   year,gender year    4   NULL    69317   Using where; Using temporary; Using filesort
10  DERIVED f   range   year,gender year    4   NULL    69317   Using where; Using temporary; Using filesort
9   DERIVED f   ref year,gender gender  257     364263  Using where; Using temporary; Using filesort
8   DERIVED f   range   year,gender year    4   NULL    94949   Using where; Using temporary; Using filesort
7   DERIVED f   ref year,gender gender  257     364263  Using where; Using temporary; Using filesort
6   DERIVED f   ref year,gender gender  257     397322  Using where; Using temporary; Using filesort
5   DERIVED f   ref year,gender gender  257     364263  Using where; Using temporary; Using filesort
4   DERIVED f   ref year,gender gender  257     397322  Using where; Using temporary; Using filesort
3   DERIVED f   ALL NULL    NULL    NULL    NULL    37045   Using where
2   DERIVED f   ALL NULL    NULL    NULL    NULL    37045   Using where

谢谢!

-b

【问题讨论】:

  • 你可以使用命令“解释”并发布输出
  • 您如何衡量select 的“超快”?是第一个结果的时间还是所有结果的时间?您可以通过添加类似order by col1 limit 1 的内容来查看需要多长时间(需要为order by 生成所有结果)。
  • 为什么你有所有这些 JOIN?由于它们是 LEFT JOIN,因此它们不会限制原始表中的匹配行。
  • 我添加了解释语句@jcho360
  • 被修改的表上是否有任何索引或(更新)触发器?

标签: mysql sql select join sql-update


【解决方案1】:

让我们考虑一下。如果您正在选择表格的行(只是抓取它们)而不是在浏览它们时更新每个...单个...行,那么需要更长的时间吗?读取 n 行还是修改(更新) n 行?

将其与阅读一本书的 10 行与在一张纸上写相同的 10 行进行比较。哪个需要更长的时间?

我还要补充一点,您阅读的行数与更新的行数越多,差异就会越大。正如一本书的阅读和写作行数会有更多差异一样,您阅读/写作的行数也越多。

【讨论】:

  • 我明白为什么需要更长的时间。我想我更感兴趣的是找出为什么它需要 so 更长的时间(如果我做的事情效率低下,我可以解决)。谢谢。
【解决方案2】:

如果这是您的实际语句,则不需要第二个和第三个 LEFT JOIN,因为它们不会改变结果。

顺便说一句,不知道 MySQL 是否能有效地处理“复杂”查询 :-) 如果你在一个临时表中实现 SELECT 的结果并使用它来代替它应该会快得多。

【讨论】:

  • 我确实有一个临时表版本,我认为它可以更快地工作,但它仍然不足:(。UPDATE 查询只是超级密集的。
  • 那你应该显示表格DDLs,肯定有问题。 SELECT 返回了多少行?
  • 什么是表 DDL? SELECT 返回与我尝试匹配的原始表相同的行数(开始中断时为 5k)
  • DDL 是数据定义语言,即 CREATE TABLE 语句。 WHERE p.requestid = '1928' 对我来说听起来像是一个非常严格的条件,5000 行很多,但仍然不足以运行几个小时。索引维护也是如此,这是额外的开销。
猜你喜欢
  • 2012-08-13
  • 2022-01-22
  • 2011-03-16
  • 2014-09-27
  • 1970-01-01
  • 1970-01-01
  • 2019-10-09
  • 1970-01-01
  • 2018-07-20
相关资源
最近更新 更多