【问题标题】:Debugging Slow mySQL query with Explain使用 Explain 调试缓慢的 mySQL 查询
【发布时间】:2016-05-10 17:01:43
【问题描述】:

在我们的系统中发现了一个效率低下的查询。 content 保存幻灯片的版本,这应该是通过 id 选择幻灯片的最高版本。

SELECT `content`.*
FROM (`content`)
JOIN (
SELECT max(version) as `version` from `content`
WHERE `slide_id` = '16901'
group by `slide_id`
) c ON `c`.`version` = `content`.`version`;

解释

+----+-------------+------------------+------------+--------+--------------------------------------------------------------------------------+------------------------------------+---------+-------+------+----------+--------------------------+
| id | select_type | table            | partitions | type   | possible_keys                                                                  | key                                | key_len | ref   | rows | filtered | Extra                    |
+----+-------------+------------------+------------+--------+--------------------------------------------------------------------------------+------------------------------------+---------+-------+------+----------+--------------------------+
|  1 | PRIMARY     | <derived2>       | NULL       | system | NULL                                                                           | NULL                               | NULL    | NULL  |    1 |   100.00 | NULL                     |
|  1 | PRIMARY     | content          | NULL       | ref    | PRIMARY,version                                                                | PRIMARY                            | 8       | const | 9703 |   100.00 | NULL                     |
|  2 | DERIVED     | content          | NULL       | ref    | PRIMARY,fk_content_slides_idx,thumbnail_asset_id,version,slide_id                      | fk_content_slides_idx              | 8       | const |    1 |   100.00 | Using where; Using index |
+----+-------------+------------------+------------+--------+--------------------------------------------------------------------------------+------------------------------------+---------+-------+------+----------+--------------------------+

一个大问题是它返回系统中几乎所有的幻灯片,因为外部查询不按幻灯片 ID 过滤。添加后我得到...

SELECT `content`.* 
FROM (`content`) 
JOIN ( 
SELECT max(version) as `version` from `content`  
WHERE `slide_id` = '16901' group by `slide_id` 
) c ON `c`.`version` = `content`.`version` 
WHERE `slide_id` = '16901';

解释

+----+-------------+------------------+------------+--------+--------------------------------------------------------------------------------+------------------------------------+---------+-------------+------+----------+--------------------------+
| id | select_type | table            | partitions | type   | possible_keys                                                                  | key                                | key_len | ref         | rows | filtered | Extra                    |
+----+-------------+------------------+------------+--------+--------------------------------------------------------------------------------+------------------------------------+---------+-------------+------+----------+--------------------------+
|  1 | PRIMARY     | <derived2>       | NULL       | system | NULL                                                                           | NULL                               | NULL    | NULL        |    1 |   100.00 | NULL                     |
|  1 | PRIMARY     | content          | NULL       | const  | PRIMARY,fk_content_slides_idx,version,slide_id                                 | PRIMARY                            | 16      | const,const |    1 |   100.00 | NULL                     |
|  2 | DERIVED     | content          | NULL       | ref    | PRIMARY,fk_content_slides_idx,thumbnail_asset_id,version,slide_id              | fk_content_slides_idx              | 8       | const       |    1 |   100.00 | Using where; Using index |
+----+-------------+------------------+------------+--------+--------------------------------------------------------------------------------+------------------------------------+---------+-------------+------+----------+--------------------------+

这可以正确地将行数减少到一个,但并没有真正加快速度。

version、slide_id 有索引,version AND slide_id 有唯一键。

我还能做些什么来加快速度吗?

使用 TOP LIMIT 1 代替 Max 吗?

米

【问题讨论】:

    标签: mysql explain mysql-slow-query-log


    【解决方案1】:

    MySQL 似乎需要一个索引(版本,slide_id)来加入表。你应该得到更好的结果

    SELECT `content`.* 
    FROM `content`
    FORCE INDEX FOR JOIN (fk_content_slides_idx) 
    join (    
        SELECT `slide_id`, max(version) as `version` from `content`  
        WHERE `slide_id` = '16901' group by `slide_id` 
    ) c ON `c`.`slide_id` = `content`.`slide_id` and `c`.`version` = `content`.`version` 
    

    您需要一个以 slide_id 作为第一列的索引,我只是猜想那是 fk_content_slides_idx,如果没有,请再取一个。

    FORCE INDEX FOR JOIN (fk_content_slides_idx)部分只是为了强制执行,如果mysql自己不强制(应该),你应该尝试一下。

    使用索引(slide_id,版本)可能会得到更好的结果,这取决于数据量(例如每个 id 的版本数),如果您发现差异(但您不应该垃圾索引,并且这张桌子上已经有很多了,但你可以试试看。)

    【讨论】:

    • 感谢@Solarfalre,现在运行速度似乎快了很多。
    【解决方案2】:

    只是一个建议,我认为您应该避免按 slide_id 分组,因为您仅按一个 slide_id 过滤(16901)

    SELECT `content`.* 
    FROM (`content`) 
    JOIN ( 
    SELECT max(version) as `version` from `content`  
       WHERE `slide_id` = '16901' 
    ) c ON `c`.`version` = `content`.`version` 
    WHERE `slide_id` = '16901';
    

    【讨论】:

      猜你喜欢
      • 2012-08-06
      • 2015-09-14
      • 2021-06-13
      • 2016-06-11
      • 2011-08-04
      • 2023-04-09
      • 1970-01-01
      • 2012-05-04
      • 2012-01-15
      相关资源
      最近更新 更多