MySQL,阅读这个EXPLAIN语句

时间:2008-10-21 15:37:30

标签: sql mysql database database-design

我的查询开始在我的应用程序中引起一些关注。我试图更好地理解这个EXPLAIN语句,以了解索引可能丢失的位置:

            +----+-------------+-------+--------+---------------+------------+---------+-------------------------------+------+---------------------------------+
            | id | select_type | table | type   | possible_keys | key        | key_len | ref                           | rows | Extra                           |
            +----+-------------+-------+--------+---------------+------------+---------+-------------------------------+------+---------------------------------+
            |  1 | SIMPLE      | s     | ref    | client_id     | client_id  | 4       | const                         |  102 | Using temporary; Using filesort |
            |  1 | SIMPLE      | u     | eq_ref | PRIMARY       | PRIMARY    | 4       | www_foo_com.s.user_id         |    1 |                                 |
            |  1 | SIMPLE      | a     | ref    | session_id    | session_id | 4       | www_foo_com.s.session_id      |    1 | Using index                     |
            |  1 | SIMPLE      | h     | ref    | email_id      | email_id   | 4       | www_foo_com.a.email_id        |   10 | Using index                     |
            |  1 | SIMPLE      | ph    | ref    | session_id    | session_id | 4       | www_foo_com.s.session_id      |    1 | Using index                     |
            |  1 | SIMPLE      | em    | ref    | session_id    | session_id | 4       | www_foo_com.s.session_id      |    1 |                                 |
            |  1 | SIMPLE      | pho   | ref    | session_id    | session_id | 4       | www_foo_com.s.session_id      |    1 |                                 |
            |  1 | SIMPLE      | c     | ALL    | userfield     | NULL       | NULL    | NULL                          | 1108 |                                 |
            +----+-------------+-------+--------+---------------+------------+---------+-------------------------------+------+---------------------------------+
            8 rows in set (0.00 sec)

我正在尝试通过阅读此EXPLAIN语句来了解我的索引缺失的位置。是否可以理解如何在不查看查询的情况下理解如何优化此查询并只查看EXPLAIN的结果?

似乎针对'c'表的ALL扫描是跟腱。根据MySQL文档中的建议,基于常量值对此进行索引的最佳方法是什么? |

注意,我还在cdr表中为userfield添加了一个索引,但是也没有做太多好处。

感谢。

---编辑---

这是查询,对不起 - 不知道为什么我在第一次通过时忽略了它。

SELECT s.`session_id` id,
                  DATE_FORMAT(s.`created`,'%m/%d/%Y') date,
                  u.`name`,
                  COUNT(DISTINCT c.id) calls,
                  COUNT(DISTINCT h.id) emails,
                  SEC_TO_TIME(MAX(DISTINCT c.duration)) duration,
                  (COUNT(DISTINCT em.email_id) + COUNT(DISTINCT pho.phone_id) > 0) status
           FROM `fa_sessions` s
           LEFT JOIN `fa_users` u ON s.`user_id`=u.`user_id`
           LEFT JOIN `fa_email_aliases` a ON a.session_id = s.session_id
           LEFT JOIN `fa_email_headers` h ON h.email_id = a.email_id
           LEFT JOIN `fa_phones` ph ON ph.session_id = s.session_id
           LEFT JOIN `fa_email_aliases` em ON em.session_id = s.session_id AND em.status = 1
           LEFT JOIN `fa_phones` pho ON pho.session_id = s.session_id AND pho.status = 1
           LEFT JOIN `cdr` c ON c.userfield = ph.phone_id
           WHERE s.`partner_id`=1
           GROUP BY s.`session_id`      

4 个答案:

答案 0 :(得分:3)

我假设你看了here以获得有关它告诉你的更多信息。显然,ALL意味着它将经历所有这些。在该页面上讨论使用临时和使用文件。你可能想看一下。

从页面:

  

使用filesort

     

MySQL必须额外通过才能找到   如何检索已排序的行   订购。排序是通过去完成的   根据连接通过所有行   键入并存储排序键和   指向所有行的行的指针   匹配WHERE子句。钥匙然后   排序并检索行   按排序顺序。见7.2.12节,   “按优化顺序”。

     

使用临时

     

要解决查询,MySQL需要   创建一个临时表来保存   结果。这通常发生在   查询包含GROUP BY和ORDER BY   以不同方式列出列的子句。

我同意看到查询可能有助于更好地解决问题。

答案 1 :(得分:3)

我的建议?

将查询分解为2并在中间使用临时表。

Reasonning

问题似乎是表c正在进行表扫描,这是查询中的最后一个表。这可能很糟糕:如果你有一个表扫描,你想在查询开始时这样做,所以它只进行一次。

我不是MySQL大师,但我花了很多时间在其他数据库上优化查询。在我看来,优化者还没有确定它应该从c开始并向后工作。

另一件令我印象深刻的事情是,联接中可能有太多表。大多数优化器都在使用超过4个表(因为可能的表命令数量呈指数增长,所以检查它们都变得不切实际了。)
在连接中有太多表是我见过的90%性能问题的根源。

试一试,让我们知道你是怎么过的。如果它没有帮助,请发布SQL,表定义和indeces,我将再看看。

一般提示

随意查看this answer我提供的一般性能提示。

一个很好的资源

MySQL Documentation for EXPLAIN

答案 2 :(得分:2)

仔细查看查询会很有用,但至少有一件事显然值得研究 - 最后一行显示查询部分的ALL类型,这通常不太好看。如果建议的可能键(userfield)作为表c的附加索引有意义,则可能值得添加它并查看是否减少了在搜索中为该表返回的行。

答案 3 :(得分:1)

查询计划

我们可能希望优化器选择的查询计划类似于:

  • sessions partner_id=1开始,可能使用partner_id,上的索引
  • 使用sessions
  • 上的索引加入usersuser_id
  • 使用sessions上的索引以及可能phones
  • status=1加入session_id,其中status
  • 使用sessionsphones上的索引再次session_id加入phone_id **
  • 使用phones
  • 上的索引将cdr加入userfield
  • 加入sessionsemail_aliases,其中status=1使用session_id上的索引,可能status
  • 使用sessionsemail_aliases上的索引再次session_id加入email_id **
  • 使用email_aliases
  • 上的索引将email_headers加入email_id

**通过在这些空格中添加2个字段,我们允许优化器使用session_id加入表格,并立即找到关联的phone_idemail_id,而无需阅读基础表。这种技术为我们节省了读数,并且可以节省大量时间。

Indeces我会创建:

上述查询计划建议使用以下内容:

fa_sessions ( partner_id, session_id )  
fa_users ( user_id )  
fa_email_aliases ( session_id, email_id )  
fa_email_headers ( email_id )  
fa_email_aliases ( session_id, status )  
fa_phones ( session_id, status, phone_id ) 
cdr ( userfield ) 

注释

  • 如果不创造所有这些,你几乎肯定会获得可接受的表现。
  • 如果任何表格很小(少于100行),则可能不值得创建索引。
  • fa_email_aliases可能与( session_id, status, email_id )一起使用,具体取决于优化器的工作方式。