【问题标题】:Optimise sql query优化sql查询
【发布时间】:2014-11-16 23:37:18
【问题描述】:

我的查询最多需要 40 秒才能执行,我想知道如何让它更快......

SELECT rp.`id` as rip,r.`id`, 
  rl.`id` as rlid, r.`number`, r.`type`, 
  a.`title` as atitle, a.`id` as aid, more, 
  more_valid 
FROM 
  `R_l_p` rp INNER JOIN 
  `Rl` rl ON rp.`rl_id` = rl.`id` INNER JOIN 
  `R` r ON r.`id` = rl.`r_id` INNER JOIN 
  `A` a ON a.`id` = r.`a_id` 
  LEFT JOIN 
   (SELECT `type`, `v`, `r_id`, COUNT(*) AS more 
    FROM `R_l` 
    WHERE `type` = 'stream' AND `v` = 1 
    GROUP BY `r_id`) stm ON stm.`r_id` = r.`id`
  LEFT JOIN 
   (SELECT `type`, `v`, `r_id`, COUNT(*) AS more_valid 
    FROM `R_l` 
    WHERE `type` = 'stream' AND `v` = 0 
    GROUP BY `r_id`) morelink ON morelink.`r_id` = r.`id`
WHERE rp.`link` = 'dead' AND rl.`type` = 'stream' 
ORDER BY rip ASC 
LIMIT 0, 1000
+-----+--------------+---------------+---------+-- ------------+-------------+----------+ ---------------+--------+------------- ---------------------------------+ |编号 |选择类型 |表|类型 |可能的键 |关键 | key_len |参考 |行 |额外 | +-----+--------------+---------------+---------+-- ------------+-------------+----------+ ---------------+--------+------------- ---------------------------------+ | 1 |初级 | r |全部 |初级,a_id |空 |空 |空 | 21804 |使用临时的;使用文件排序 | | 1 |初级 |一个 | eq_ref |初级 |初级 | 4 | db453988339.r.a_id | 1 | | | 1 |初级 | rl |参考 | PRIMARY,r_id,类型 | r_id | 4 | db453988339.r.id | 1 |使用位置 | | 1 |初级 |派生2 |全部 |空 |空 |空 |空 | 21077 | | | 1 |初级 |派生3 |全部 |空 |空 |空 |空 | 1 | | | 1 |初级 | rp | eq_ref | rl_id | rl_id | 4 | db453988339.rl.id | 1 |使用位置 | | 3 |派生 |链接 |全部 |类型 |空 |空 |空 | 27580 |使用哪里;使用临时的;使用文件排序 | | 2 |派生 |链接 |全部 |类型 |空 |空 |空 | 27580 |使用哪里;使用临时的;使用文件排序 | +-----+--------------+---------------+---------+-- ------------+-------------+----------+ ---------------+--------+------------- ---------------------------------+

谢谢你:)

【问题讨论】:

  • 删除这 2 个左连接后查询的执行情况如何?
  • 左连接的意义何在?你在任何地方都没有提到他们
  • 他使用左侧连接中的 more 和 more_valid 作为 select 子句的结果
  • 是 v 列位吗?还是 R_l 表有不同的结果?
  • @Leo,在没有两个左连接(0.04 秒)的情况下它的性能非常好。但我真的需要这些...... FuzzyTree,越来越多的_valid 来自这两个左连接

标签: mysql sql performance join time


【解决方案1】:

一方面,我会用一个内联视图替换两个内联视图,通过将 WHERE 子句中的条件移动到 SELECT 列表中的表达式中,从同一个内联视图返回 moremore_valid),并消除more_link 视图。

我会将stm 内联视图修改为如下所示:

       ( SELECT q.r_id
              , SUM(q.v=1) AS `more`
              , SUM(q.v=0) AS `more_valid`
           FROM `R_l` q
          WHERE q.type = 'stream'
          GROUP BY q.r_id
       ) stm

我还会提供一个覆盖索引来优化该内联视图查询,例如:

    CREATE INDEX R_1_IX1 ON R_1 (type, r_id, v)

使用前导列type 上的相等谓词,MySQL 可能能够使用索引优化 GROUP BY 操作(避免“使用文件排序”操作)。我们希望在说明的额外列中看到“使用索引”。

很遗憾,派生表不会被索引。但至少通过这种更改,您只实现了一个内联视图,避免了额外的连接操作。


也就是说,我会替换这两行:

LEFT JOIN (SELECT `type`, `v`, `r_id`, COUNT(*) AS more FROM `R_l` WHERE `type` = 'stream' AND `v` = 1 GROUP BY `r_id`) stm ON stm.`r_id` = r.`id`
LEFT JOIN (SELECT `type`, `v`, `r_id`, COUNT(*) AS more_valid FROM `R_l` WHERE `type` = 'stream' AND `v` = 0 GROUP BY `r_id`) morelink ON morelink.`r_id` = r.`id`

有了这个:

  LEFT
  JOIN ( SELECT q.r_id
              , SUM(q.v=1) AS `more`
              , SUM(q.v=0) AS `more_valid`
           FROM `R_l` q
          WHERE q.type = 'stream'
          GROUP BY q.r_id
       ) stm
    ON stm.r_id =  r.id

【讨论】:

  • 我应该添加索引,即使我已经有一个用于类型、r_id 和 v 的索引?
  • 从 40 秒到 2 秒更好。谢谢
  • @cloud1250000:“使用文件排序”操作可能很昂贵,尤其是在大型集合上。有时可以让 MySQL 避免该操作,并使用索引。 (当需要“分组”在一起的行在索引中是连续的时,MySQL可以在不物化行的情况下得到结果;当查询可以仅从索引中得到满足时,无需查找底层的数据页表,这称为“覆盖”索引,我们将在 EXPLAIN 输出中看到“使用索引”。但是,连接到该派生表仍然会很昂贵。
  • @cloud1250000:注意:我建议的更改可能会为more 和/或more_valid 返回 NULL 而不是 0,或者可能返回零而不是 NULL。 (我想它会,然后我决定它不会;我现在不确定。使用IFNULL(SUM(q.v=1),0) 让它返回 0 而不是 NULL 不会花费任何成本。你仍然可以获得如果没有匹配的行,则在外部查询中为 NULL,您可以在外部查询中轻松地使用 IFNULL(more,0) AS more
  • 好吧,现在真的一点也不差。谢谢;) 我已经添加了索引和所有内容。效果很好:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-10
  • 2014-02-04
  • 2011-06-22
  • 2015-08-10
相关资源
最近更新 更多