在查询的时候,如果数据全部可以从索引中读取,无需再取其他的行数据(避免了磁盘IO),那么无疑,速度将会飞快。
select user_name from user where user_id=3;
如果有个索引 (user_id,user_name)
就可以做到索引覆盖。
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 的硬盘会快点。
上面的例子中,一定要所有的列的排序顺序都相同,才可以。
MySQL 中的绝大部分的索引,都是 B+Tree。所以,既可以快速查找某个值,又可以做排序。
where a=3
where a like 'The big%'
where a between 3 and 8
另一种索引是 Hash 索引,这种索引只可以快速查找,不能用于排序。
where id+1=5 -- MySQL 并不知道是 id = 4
where to_days(curent_date) - to_days(create_time) <= 10 -- create_time < ? 最好了
总之一句话,尽量不要在where条件中做计算、写表达式。
*count() vs count(id)** 一个常见的误解就是认为 count(id) 会快于 count(*) 但这个星号却并不会自动展开,MySQL统计的就是结果集的行数,并不会真的获取结果集。
count(col) 如果 col 可能为 NULL,结果就是NULL的列不会被计数。
使用 InnoDB 的时候,count(*)可能会带来全表扫描。如果对精确度的要求不是太高,可以使用 Explain 语句。
如果非要精确,但是又需要高性能,可以增加汇总表。
“快速,精确,实现简单”,永远只能满足其二。
假如我们想查询每个演员演了几部电影:
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;
在一个标识列上做分组,会更加高效。