小池有话说

《高性能 MySQL》读书笔记(草稿)

2014-08-15

空间占用和精度

索引

索引覆盖

在查询的时候,如果数据全部可以从索引中读取,无需再取其他的行数据(避免了磁盘IO),那么无疑,速度将会飞快。

select user_name from user where user_id=3;

如果有个索引 (user_id,user_name) 就可以做到索引覆盖。

file sort

file sort 不可望文生义,并不是磁盘排序的意思。而是需要做额外的排序的意思。有的时候,这个额外排序是内部排序,在内存中完成,有的时候是外部排序,这个时候就是名副其实的 file sort 了。有没有不需要做额外的排序的呢?当然有。

select user_name from user order by last_login_time desc;

假如有个索引 (last_login_time desc),那么我们就不用 file sort 了。

假如有以下语句,要做到索引覆盖,我们需要什么索引呢?

select user_name from user where group_id=3 order by last_login_time desc

答案是 (group_id,last_login_time desc, user_name),你答对了吗?

排序

MySQL 中的排序有两种

如果 Explain 中的 type 列的值为 index,则说明MySQL使用了索引扫描来做排序,更加快速。

如果索引不能覆盖所有所需的列,那么不得不每扫描一条索引记录就回表查询一行。这个基本上是随机 I/O,所以用 SSD 的硬盘会快点。

上面的例子中,一定要所有的列的排序顺序都相同,才可以。

B树

MySQL 中的绝大部分的索引,都是 B+Tree。所以,既可以快速查找某个值,又可以做排序。

另一种索引是 Hash 索引,这种索引只可以快速查找,不能用于排序。

一些禁令

where id+1=5 -- MySQL 并不知道是 id = 4
where to_days(curent_date) - to_days(create_time) <= 10 -- create_time < ? 最好了

总之一句话,尽量不要在where条件中做计算、写表达式。

count

*count() vs count(id)** 一个常见的误解就是认为 count(id) 会快于 count(*) 但这个星号却并不会自动展开,MySQL统计的就是结果集的行数,并不会真的获取结果集。

count(col) 如果 col 可能为 NULL,结果就是NULL的列不会被计数。

使用 InnoDB 的时候,count(*)可能会带来全表扫描。如果对精确度的要求不是太高,可以使用 Explain 语句。

如果非要精确,但是又需要高性能,可以增加汇总表。

“快速,精确,实现简单”,永远只能满足其二。

group by

假如我们想查询每个演员演了几部电影:

select name, count(*)
from film_actor
inner join actor using(actor_id)
group by actor.name;

这个查询的语义非常清晰,但是,效率不高。

select name, count(*)
from film_actor
inner join actor using(actor_id)
group by actor.actor_id; 

在一个标识列上做分组,会更加高效。