原文链接:http://www.xaprb.com/blog/2009/04/01/how-mysql-really-executes-a-query/
注:作者说了,很多地方是愚人节的玩笑...
让我们看看它是如何从开始到结束的。
SELECT SQL_NO_CACHE COUNT(col1) FROM users
WHERE userid IN(
SELECT userid FROM othertbl
)
ORDER BY userid DESC;
执行这个查询可以分为以下的几步:
1. MySQL API将查询分解成一系列标记并发送到server。
2. 解析查询
3. MySQL进行权限检查。由于可能要调用一次LDAP或者活动目录,所以此步比较复杂。这里先注释掉这一步。
4. 查询缓存进行检查。但是由于我明确的给出了SQL_NO_CACHE的指令,所以查询缓存再次并不检查。(如果没有给出SQL_NO_CACHE指令,可能会在缓存中找到一个结果集并返回它。)
5. 优化器执行子查询并返回userid值的列表替换掉IN表达式。
6. 优化器开始处理COUNT 表达式。就我们所知,所有的COUNT查询在MyISAM表上都能被非常快速的执行,但又有InnoDB并没有优化器,所以在InnoDB上COUNT是比较慢的。实际上,InnoDB在各方面都比MyISAM慢,所以应该经常使用MyISAM。
7. 经过解析并优化的查询被编译成查询计划(query plan | 译者: execution plan)—— 本地的字节码,可以直接在CPU上执行。
8. 优化过的查询计划被保存下来留为之后的查询用。如果稍后一个相似的查询发送过来,解析和编译可以被省略。而令人奇怪的是,这些都是存放在查询缓存中的。(这仅仅是那些存放在查询缓存中有趣的之一,正如我所说,执行可能并不如你所愿)
9. 查询被执行,可能是多个CPU同时执行。如果这样的话,多个CPU的放回结果需要被结合成最终结果。此处的操作会显示在Sort_merge_passes状态中。(这就是为什么sort_buffer_size要设置的比较大,一般我推荐是可用内存的75%或者更多。)
10. 如果userid列上没有索引,那么 ORDER BY 会被忽略。但如果有索引的话,MySQL的行锁和MVCC(server实现,并不在存储引擎中)将强制从索引中读取结果。在这种情况下,结果会被放置到一个文件中并被排序,内部名称是“filesort”,可以在EXPLAIN的输出中看到。
11. 如果结果集比server的内存大,server也必须在磁盘上创建临时表。那样,在EXPLAIN的输出中将可以看到“Using temporary; Using disk table”。
12. 通过一个分离的网络连接返回结果集给客户端(如此,查询才能异步)。
13. 查询结束后,记录在MyISAM的事务日志——binary log中。如果你记录了这些log,你可以撤销之前执行的语句,如此便不需要备份了。可以仅仅用binary log来回滚修改。binary log也是MyISAM的优势之一。