sql执行顺序
了解索引优化需要首先知道搜吸引的执行顺序。
书写顺序如下:
select[distinct]
from
join(如left join)
on
where
group by
having
union
order by
limit
实际执行顺序如下:
from
on
join
where
group by
having
select
distinct
union
order by
sql执行顺序
七种JOIN
left /right/inner join
mysql不支持full outer join语法,使用union连接
索引
概念:
数据库内存储着数据本身之外,还存储着特定查找算法的数据结构,该数据结构以某种方式指向数据。
索引本质就是高效获取数据的数据结构。该数据结构两大功能:排序和查找(where后面的查找和order by后面的排序)。
左边为数据(包含物理地址和存储的数据),右边为索引
索引为二叉查找树,每个节点包含索引键值和指向对应数据的物理地址的指针。MySQL中的索引的存储类型有两种:BTREE、HASH
优缺点:
- 优点:
- 加快数据的查询速度
- 降低排序CPU消耗
- 缺点:
- 创建索引和维护索引要耗费时间,并且随着数据量的增加所耗费的时间也会增加
- 索引也需要占空间,如果有大量的索引,索引文件可能会比数据文件更快达到上限值
- 当对表中的数据进行增加、删除、修改时,索引也需要动态的维护,降低了数据的维护速度
使用原则
- 对经常更新的表就避免对其进行过多的索引,对经常用于查询的字段应该创建索引,
- 数据量小的表最好不要使用索引,因为由于数据较少,可能查询全部数据花费的时间比遍历索引的时间还要短,索引就可能不会产生优化效果
- 在一同值少的列上(字段上)不要建立索引,比如在学生表的"性别"字段上只有男,女两个不同值。相反的,在一个字段上不同值较多可以建立索引
索引分类
- 单值索引(普通索引,唯一索引,主键索引)
一个索引只包含单个列,但一个表中可以有多个单列索引。
唯一索引:索引列中的值必须是唯一的,但是允许为空值。
主键索引:是一种特殊的唯一索引,不允许有空值。
- 复合索引
在表中的多个字段组合上创建的索引,只有在查询条件中使用了这些字段的左边字段时,索引才会被使用,使用组合索引时遵循最左前缀集合。
create index id_name_subject on teacher(name, subject);
//mysql会先比较name,如果name一样,再比较subject。
- 唯一索引
- 全文索引
全文索引,只有在MyISAM引擎上才能使用,只能在CHAR,VARCHAR,TEXT类型字段上使用。
在一堆文字中,通过其中的某个关键字等,就能找到该字段所属的记录行,比如有"你是个靓仔,靓女 ..." 通过靓仔,可能就可以找到该条记录
- 空间索引
空间索引是对空间数据类型的字段建立的索引,MySQL中的空间数据类型有四种,GEOMETRY、POINT、LINESTRING、POLYGON。在创建空间索引时,使用SPATIAL关键字。要求,引擎为MyISAM,创建空间索引的列,必须将其声明为NOT NULL聚集索引(clustered index):聚集索引决定数据在磁盘上的物理排序,一个表只能有一个聚集索引,一般用primary key来约束(t_user场景中,uid上的索引)。
非聚集索引(non-clustered index):它并不决定数据在磁盘上的物理排序,索引上只包含被建立索引的数据,以及一个行定位符row-locator,这个行定位符,可以理解为一个聚集索引物理排序的指针,通过这个指针,可以找到行数据(查找年轻MM的业务需求):
select uid from t_user where age > 18 and age < 26;
age上建立的索引,就是非聚集索引。
其他概念
最左前缀匹配(leftmost prefix)
一个表的a,b,c三个字段建了索引:
create index id_a_b_c on foo(a, b, c);
那么当你where条件是a或者a、b或者a、b、c时,都可以命中索引,除此之外,都不能命中索引,比如a、c,或者b、c等(带头大哥不能死,中间兄弟不能断)
聚簇索引和二级索引:
覆盖索引:
当要select的字段,已经在索引树里面存储,那就不需要再去检索数据库。
//a、b、c三个字段建了复合索引,下面就可以覆盖索引
select b,c from foo where a = "xxx";
索引失效场景
-
WHERE
字句的查询条件里有不等于号/大于小于(WHERE column!=…
)造成失效; - 对索引进行运算,类型转换等,将造成失效;
- 在
JOIN
操作中(需要从多个数据表提取数据时),MYSQL
只有在主键和外键的数据类型相同时才能使用索引,否则即使建立了索引也不会使用; - 范围之后全失效;
- isnull/isnotnull也无法使用索引;
- 如果
WHERE
子句的查询条件里使用了比较操作符LIKE
和REGEXP
,MYSQL
只有在搜索模板的第一个字符不是通配符的情况下才能使用索引(如果查询条件是LIKE 'abc%',MYSQL将使用索引;如果条件是LIKE '%abc',MYSQL将不使用索引)使用索引覆盖会避免两边%引起的索引失效。 - 如果某个数据列里包含着许多重复的值,就算为它建立了索引也不会有很好的效果。比如说,如果某个数据列里包含了净是些诸如
“0/1”
或“Y/N”
等值,就没有必要为它创建一个索引。 - 如果条件中有
or
(并且其中有or
的条件是不带索引的),即使其中有条件带索引也不会使用(这也是为什么尽量少用or
的原因)。注意:要想使用or
,又想让索引生效,只能将or
条件中的每个列都加上索引 - 如果列类型是字符串,那一定要在条件中将数据使用引号引用起来,否则不使用索引
练习
分组之前必排序
建立顺序c1,c2,c3,c4