10

我有一个与解释相关的基本 MySQL 性能问题。我有两个返回相同结果的查询,我试图了解如何理解EXPLAIN执行计划。

该表中有 50000 条记录,我正在执行记录比较。我的第一个查询需要 18.625 秒才能运行。解释计划如下。

id  select_type table   type    possible_keys                   key         key_len ref                                 rows    filtered    Extra
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
1   SIMPLE      a       ALL     NULL                            NULL        NULL    NULL                                49520   100.00  
1   SIMPLE      b       ref     scoreEvent,eventScore           eventScore  4       olympics.a.eventId                  413     100.00      Using where; Using index; Not exists
1   SIMPLE      c       ref     PRIMARY,scoreEvent,eventScore   scoreEvent  8       olympics.a.score,olympics.a.eventId 4       100.00      Using where; Using index; Not exists

我的下一个查询需要 0.106 秒才能运行...

id  select_type table       type    possible_keys   key     key_len     ref     rows    filtered    Extra
-----------------------------------------------------------------------------------------------------------------------------------
1   PRIMARY     <derived2>  ALL     NULL            NULL    NULL        NULL    50000   100.00      Using temporary; Using filesort
2   DERIVED     results     ALL     NULL            NULL    NULL        NULL    49520   100.00      Using filesort

在文档中它说ALL需要进行全表扫描,这非常糟糕。它还说filesort需要额外的传递来对记录进行排序,它还说这Not exists意味着 MySQL 能够进行LEFT JOIN优化。很明显,第一种方法使用索引,而第二种方法没有。

我试图弄清楚这里发生了什么以及涉及到什么数学。我RESET QUERY CACHE在测试之间跑来跑去,以确保不会获得任何不公平的优势。49520 x 413 x 4 比 50000 x 49520 小很多。

id解释计划中的有关吗?

当我测试这些和其他查询时,我的观察似乎是查询复杂性可以通过将具有相同 id 的项目相乘并将每个 id 的结果加在一起来近似......这是一个有效的假设吗?


额外的

按照评论中的要求,架构和查询以防万一,但我不是在寻找更好的查询......只是对EXPLAIN. 有问题的表...

CREATE TABLE results (
  resultId INT NOT NULL auto_increment KEY, 
  athleteId INT NOT NULL,
  eventId INT NOT NULL,
  score INT NOT NULL,
  CONSTRAINT FOREIGN KEY (athleteId) REFERENCES athletes(athleteId),
  CONSTRAINT FOREIGN KEY (eventId) REFERENCES events(eventId),
  INDEX eventScore (eventId, score),
  INDEX scoreEvent (score, eventId)
) ENGINE=innodb;

第一个查询...

SELECT a.resultId, a.eventId, a.athleteId, a.score
FROM results a 

-- Find records with matching eventIds and greater scores
LEFT JOIN results b 
ON b.eventId = a.eventId 
AND b.score > a.score

-- Find records with matching scores and lesser testIds
LEFT JOIN results c
ON c.eventId = a.eventId
AND c.score = a.score
AND c.resultId < a.resultId

-- Filter out all records where there were joins
WHERE c.resultId IS NULL 
AND b.resultId IS NULL;

第二个查询...

SELECT resultId, athleteId, eventId, score
FROM (
  SELECT resultId, athleteId, eventId, score
  FROM results
  ORDER BY eventId, score DESC, resultId
) AS a
GROUP BY eventId;

我还注意到,如果我删除索引eventScore,查询下降到 2.531 秒并且执行计划没有太大变化,但是 possible_keys 的顺序发生了变化并且它不适Using index用于表b(忽略我正在生成的行数的细微变化每次更改架构时的数据)...

id  select_type table   type    possible_keys               key         key_len ref                                 rows    filtered    Extra
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
1   SIMPLE      a       ALL     NULL                        NULL        NULL    NULL                                47457   100.00  
1   SIMPLE      b       ref     eventId,scoreEvent          eventId     4       olympics.a.eventId                  659     100.00      Using where; Not exists
1   SIMPLE      c       ref     PRIMARY,eventId,scoreEvent  scoreEvent  8       olympics.a.score,olympics.a.eventId 5       100.00      Using where; Using index; Not exists
4

2 回答 2

4

实际上,当您看到时,您不应该乘以,而是将这些数字相加。在您的情况下,比较 (49520 x 413 x 4) 和 (50000 + 49520)。

一般规则很简单:汇总所有段(DERIVED、PRIMARY)并在每个段中乘以行。

id select_type  ... rows
1  PRIMARY           1
1  PRIMARY           2
2  DERIVED           3
2  DERIVED           4
3  DERIVED           5
3  DERIVED           6

复杂度为:1*2 + 3*4 + 5*6

于 2013-05-16T19:07:10.300 回答
0

不要太相信 EXPLAIN 的“rows”语句。如在 mysql 文档中:“估计要检查的行数”(http://dev.mysql.com/doc/refman/5.1/en/explain-output.html)。

也许更新你的索引统计数据会给你一个更好的估计(优化表,http ://dev.mysql.com/doc/refman/5.0/en/optimize-table.html )

于 2013-04-28T10:09:10.940 回答