1、索引介绍mysql
索引可让数据库加快查询速度,可是却会减慢数据的插入速度。由于每次插入一个数据,都要从新处理一次索引。算法
索引是利用不断缩小查询范围,去除不相关数据来找到目标数据。sql
索引使用B+树算法,把索引分层次存储,每次加载一个磁盘块进入内存中(根节点),进行比较,找到对应范围内的指针,而后再去加载另外一块磁盘块(枝节点),找到所对应的指针,一直找到最底层叶子节点。数据库
如上图是一颗B+树,最上层是根节点,中间是枝节点,最下层是叶子节点。如今假设查找数据项28,先把磁盘块1加载到内存中,数据项28跟数据项17和数据项35比较,能够看到28处于中间,那么就能够去除掉小于17和大于35的部分了。而后,也找到了P2,P2指针对应的磁盘块3。再把磁盘块3加载到内存中,28在26和30之间,这样又除去了小于26和大于30的部分。也找到了指针P2,以及P2指示的数据块8,再把磁盘块8加载到内存中,找到了数据块28。函数
B+树的性质:spa
索引的最左匹配特性:B+树搜索数据时,是从左往右比对,而后根据表中字段顺序依次比对的。指针
索引的两大类型:blog
#咱们能够在建立上述索引的时候,为其指定索引类型,分两类hash类型的索引:查询单条快,范围查询慢排序
btree类型的索引:b+树,层数越多,数据量指数级增加(咱们就用它,由于innodb默认支持它)索引
#不一样的存储引擎支持的索引类型也不同
InnoDB 支持事务,支持行级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
MyISAM 不支持事务,支持表级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
2、汇集索引和辅助索引
数据库中的索引能够分为汇集索引和辅助索引:
(1)汇集索引和辅助索引的相同点是:无论是汇集索引仍是辅助索引,其内部都是B+树形式,就是树的高度(或层数)是同样的,叶子结点中存放着全部的数据。
(2)汇集索引和辅助索引的不一样点是:叶子节点存放的是不是一整行的信息。(汇集索引存放的是一整行,辅助索引存放的是一部分。)
1.汇集索引
汇集索引就是不可为空且是惟一的一个字段,最好这个字段在内存中所占空间越小越好。
汇集索引的好处之一:它对主键的排序查找和范围查找速度很是快,叶子节点的数据就是用户所要查询的数据。
汇集索引的好处之二:范围查询(range query),即若是要查找主键某一范围内的数据,经过叶子节点的上层中间节点就能够获得页的范围,以后直接读取数据页便可
辅助索引的叶子节点中存储的是主键,而后再使用这个主键走一遍“根节点-->枝节点-->叶子结点”的过程。这样作会增长一倍的IO操做,可是相对于从头走到尾那样的查询,而且每次都要操做IO的方式,这样作是完胜的。
3、实际操做
普通索引INDEX:加速查找
惟一索引:
-主键索引PRIMARY KEY:加速查找+约束(不为空、不能重复)
-惟一索引UNIQUE:加速查找+约束(不能重复)
联合索引:
-PRIMARY KEY(id,name):联合主键索引
-UNIQUE(id,name):联合惟一索引
-INDEX(id,name):联合普通索引
汇集索引:
(1) 建立表时,直接建立出来:create table t2(id int primary key,name char(10),age int, class int ,index in_age(age));
惟一索引:
(1) 表建立好后,再去添加惟一索引: alter table t2 add unique key un_class(class);
辅助索引:
(1) 表建立好后,再去添加辅助索引:create index in_name on t2(name);
汇集索引:
(1)alter table t2 drop primary key;
辅助索引:
(1) drop index in_name on t2;
(2) alter table t2 drop index in_name;
惟一索引:
(1)alter table t2 drop index un_class;
4、正确使用索引
并非说咱们建立了索引就必定会加快查询速度,若想利用索引达到预想的提升查询速度的效果,咱们在添加索引时,必须遵循如下问题
一、 范围问题,或者说条件不明确,条件中出现这些符号或关键字:>、>=、<、<=、!= 、between...and...、like、大于号、小于号
例如:若是写成where id >1 and id <1000000;会发现,随着你范围的增大,速度会愈来愈慢,会成倍的体现出来。
二、 不等于!=,比等于要多费时间。
三、 between ...and... 和大于小于同样,范围越小查询速度越快。
四、 like匹配的值里若是后面没有%,那么和=是同样的,速度很快。若是有%,那么速度也很快,会去迅速匹配相应的记录,可是若是%在开始位置,就至关于这个值会与每行记录进行比较一下。因此%在开始位置时,会使查询速度变慢。
五、 =和in能够乱序:
好比a = 1 and b = 2 and c = 3 ,a,b,c的位置能够随意排;
in (b,c,a)in后面的a,b,c也是能够打乱顺序的。
六、 索引列不能参与计算,保持列“干净”:
where id = 1000;这样的条件,能够很容易的对比出来,而后取出这一行的记录。
可是,where id*3 = 10000,这样的计算就会致使每次对比前都得先计算一下id的值是多少,所以就不能发挥出索引快速查询的做用了。
把上面的条件写成 where id = 3000/3;你会发现速度变得很快,由于等于号后面的数字,是在比较以前就计算出来了,不须要每次都计算一次每次都计算一次了,跟直接等于一个常数是同样的,因此很快。结论是不要让你的索引字段参与到计算中。
七、 and和or
a=2 and b>3 and c=4,像这样and的工做原理是,先按照最左原则,从左往右先找出区分度高的把范围缩小,而后再去查找其余的条件。
区分度=count(distinct 字段)/count(*) 值越大,区分度越高,值越小,区分度越低。
a=2 or b>3 or c=4,像这样or的工做原理是,按照最左原则,先判断第一个条件是否成立,若是成立那么就中止,不成立的话,再对比第二个,这样依次比较下去。
八、 最左前缀匹配原则,很是重要的原则,对于组合索引mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就中止匹配(指的是范围大了,有索引速度也慢),好比a = 1 and b = 2 and c > 3 and d = 4 若是创建(a,b,c,d)顺序的索引,d是用不到索引的,若是创建(a,b,d,c)的索引则均可以用到,a,b,d的顺序能够任意调整。
九、 其余状况
- 使用函数
select * from tb1 where reverse(email) = 'egon';
- 类型不一致
若是列是字符串类型,传入条件时必须用引号引发来,否则报错: Unknown column 'xx' in 'where clause'
select * from tb1 where email = 999;
#排序条件为索引,则select字段必须也是索引字段,不然没法命中
- order by
select name from s1 order by email desc;
当根据索引排序时候,select查询的字段若是不是索引,则速度仍然很慢。这与B+树有关,普通索引的叶子节点中只是保存了汇集索引的值,因此会回表。
select email from s1 order by email desc;
特别的:若是对主键排序,则仍是速度很快:
select * from tb1 order by nid desc;
由于在B+树的叶子节点中,存储的是那一行记录的索引,找到了主键索引就找到了行记录。
- 组合索引最左前缀
若是组合索引为:(name,email)
name and email -- 命中索引
name -- 命中索引
email -- 未命中索引
- count(1)或count(列)代替count(*)在mysql中没有差异了
- create index xxxx on tb(title(19)) #text类型,必须制定长度。
- 避免使用select *
- count(1)或count(列) 代替 count(*)
- 建立表时尽可能时 char 代替 varchar
- 表的字段顺序固定长度的字段优先
- 组合索引代替多个单列索引(常用多个条件查询时)
- 尽可能使用短索引
- 使用链接(JOIN)来代替子查询(Sub-Queries)
- 连表时注意条件类型需一致- 索引散列值(重复少)不适合建索引,例:性别不适合
5、联合索引和覆盖索引
一、联合索引
mysql> create table t( -> a int, -> b int, -> primary key(a), -> key idx_a_b(a,b) -> );
那么什么时候须要使用联合索引呢?在讨论这个问题以前,先来看一下联合索引内部的结果。从本质上来讲,联合索引就是一棵B+树,不一样的是联合索引的键值得数量不是1,而是>=2。接着来讨论两个整型列组成的联合索引,假定两个键值得名称分别为a、b如图:
能够看到这与咱们以前看到的单个键的B+树并无什么不一样,键值都是排序的,经过叶子结点能够逻辑上顺序地读出全部数据,就上面的例子来讲,即(1,1),(1,2),(2,1),(2,4),(3,1),(3,2),数据按(a,b)的顺序进行了存放。
所以,对于查询select * from table where a=xxx and b=xxx, 显然是可使用(a,b) 这个联合索引的,对于单个列a的查询select * from table where a=xxx,也是可使用(a,b)这个索引的。
但对于b列的查询select * from table where b=xxx,则不可使用(a,b) 索引,其实你不难发现缘由,叶子节点上b的值为一、二、一、四、一、2显然不是排序的,所以对于b列的查询使用不到(a,b) 索引。
注意创建联合索引的一个原则:索引是有个最左匹配的原则的,因此建联合索引的时候,将区分度高的放在最左边,依次排下来,范围查询的条件尽量的日后边放。
联合索引的第二个好处是在第一个键相同的状况下,已经对第二个键进行了排序处理,例如在不少状况下应用程序都须要查询某个用户的购物状况,并按照时间进行排序,最后取出最近三次的购买记录,这时使用联合索引能够帮咱们避免多一次的排序操做,由于索引自己在叶子节点已经排序了。
2.覆盖索引
InnoDB存储引擎支持覆盖索引(covering index,或称索引覆盖),即从辅助索引中就能够获得查询记录,而不须要查询汇集索引中的记录。
使用覆盖索引的一个好处是:辅助索引不包含整行记录的全部信息,故其大小要远小于汇集索引,所以能够减小大量的IO操做。