我的查询开始在我的应用程序中引起一些关注。我试图更好地理解这个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`
答案 0 :(得分:3)
我假设你看了here以获得有关它告诉你的更多信息。显然,ALL意味着它将经历所有这些。在该页面上讨论使用临时和使用文件。你可能想看一下。
从页面:
使用filesort
MySQL必须额外通过才能找到 如何检索已排序的行 订购。排序是通过去完成的 根据连接通过所有行 键入并存储排序键和 指向所有行的行的指针 匹配WHERE子句。钥匙然后 排序并检索行 按排序顺序。见7.2.12节, “按优化顺序”。
使用临时
要解决查询,MySQL需要 创建一个临时表来保存 结果。这通常发生在 查询包含GROUP BY和ORDER BY 以不同方式列出列的子句。
我同意看到查询可能有助于更好地解决问题。
答案 1 :(得分:3)
将查询分解为2并在中间使用临时表。
问题似乎是表c正在进行表扫描,这是查询中的最后一个表。这可能很糟糕:如果你有一个表扫描,你想在查询开始时这样做,所以它只进行一次。
我不是MySQL大师,但我花了很多时间在其他数据库上优化查询。在我看来,优化者还没有确定它应该从c开始并向后工作。
另一件令我印象深刻的事情是,联接中可能有太多表。大多数优化器都在使用超过4个表(因为可能的表命令数量呈指数增长,所以检查它们都变得不切实际了。)
在连接中有太多表是我见过的90%性能问题的根源。
试一试,让我们知道你是怎么过的。如果它没有帮助,请发布SQL,表定义和indeces,我将再看看。
随意查看this answer我提供的一般性能提示。
答案 2 :(得分:2)
仔细查看查询会很有用,但至少有一件事显然值得研究 - 最后一行显示查询部分的ALL类型,这通常不太好看。如果建议的可能键(userfield)作为表c的附加索引有意义,则可能值得添加它并查看是否减少了在搜索中为该表返回的行。
答案 3 :(得分:1)
我们可能希望优化器选择的查询计划类似于:
sessions
partner_id=1
开始,可能使用partner_id,
上的索引sessions
users
到user_id
sessions
上的索引以及可能phones
status=1
加入session_id
,其中status
sessions
和phones
上的索引再次session_id
加入phone_id
** phones
cdr
加入userfield
sessions
到email_aliases
,其中status=1
使用session_id
上的索引,可能status
sessions
和email_aliases
上的索引再次session_id
加入email_id
** email_aliases
email_headers
加入email_id
**通过在这些空格中添加2个字段,我们允许优化器使用session_id
加入表格,并立即找到关联的phone_id
或email_id
,而无需阅读基础表。这种技术为我们节省了读数,并且可以节省大量时间。
上述查询计划建议使用以下内容:
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 )
fa_email_aliases
可能与( session_id, status, email_id )
一起使用,具体取决于优化器的工作方式。