解释MySQL解释执行计划的数学,两个计划之间的区别

Stu*_*eld 10 mysql performance explain sql-execution-plan

我有一个与解释相关的基本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
Run Code Online (Sandbox Code Playgroud)

我的下一个查询需要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
Run Code Online (Sandbox Code Playgroud)

在文档中,它说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;
Run Code Online (Sandbox Code Playgroud)

第一个查询......

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;
Run Code Online (Sandbox Code Playgroud)

第二个问题......

SELECT resultId, athleteId, eventId, score
FROM (
  SELECT resultId, athleteId, eventId, score
  FROM results
  ORDER BY eventId, score DESC, resultId
) AS a
GROUP BY eventId;
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

Ale*_*zin 4

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

一般规则很简单:汇总所有段(派生的、主要的)并在每个段内乘以行。

id select_type  ... rows
1  PRIMARY           1
1  PRIMARY           2
2  DERIVED           3
2  DERIVED           4
3  DERIVED           5
3  DERIVED           6
Run Code Online (Sandbox Code Playgroud)

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