(三十八)索引

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

  1. 索引字段要尽可能的小由于磁盘块的大小是固定的,只有索引字段越小,能够存储的越多。

索引的最左匹配特性B+树搜索数据时,是从左往右比对,而后根据表中字段顺序依次比对的。指针

索引的两大类型:blog

#咱们能够在建立上述索引的时候,为其指定索引类型,分两类hash类型的索引:查询单条快,范围查询慢排序

btree类型的索引:b+树,层数越多,数据量指数级增加(咱们就用它,由于innodb默认支持它)索引

 

#不一样的存储引擎支持的索引类型也不同

InnoDB 支持事务,支持行级别锁定,支持 B-treeFull-text 等索引,不支持 Hash 索引;

MyISAM 不支持事务,支持表级别锁定,支持 B-treeFull-text 等索引,不支持 Hash 索引;

 

2、汇集索引和辅助索引

 

数据库中的索引能够分为汇集索引和辅助索引:

 

(1)汇集索引和辅助索引的相同点是:无论是汇集索引仍是辅助索引,其内部都是B+树形式,就是树的高度(或层数)是同样的,叶子结点中存放着全部的数据。

 

(2)汇集索引和辅助索引的不一样点是:叶子节点存放的是不是一整行的信息。(汇集索引存放的是一整行,辅助索引存放的是一部分。)

 


1.汇集索引

 

汇集索引就是不可为空且是惟一的一个字段,最好这个字段在内存中所占空间越小越好。

 

汇集索引的好处之一:它对主键的排序查找和范围查找速度很是快,叶子节点的数据就是用户所要查询的数据

 

汇集索引的好处之二:范围查询(range query),即若是要查找主键某一范围内的数据,经过叶子节点的上层中间节点就能够获得页的范围,以后直接读取数据页便可

 

  1. 辅助索引

 

辅助索引的叶子节点中存储的是主键,而后再使用这个主键走一遍“根节点-->枝节点-->叶子结点”的过程。这样作会增长一倍的IO操做,可是相对于从头走到尾那样的查询,而且每次都要操做IO的方式,这样作是完胜的。

 

3、实际操做

   普通索引INDEX:加速查找

惟一索引:

    -主键索引PRIMARY KEY:加速查找+约束(不为空、不能重复)

   -惟一索引UNIQUE:加速查找+约束(不能重复)

 

联合索引:

    -PRIMARY KEY(id,name):联合主键索引

    -UNIQUE(id,name):联合惟一索引

    -INDEX(id,name):联合普通索引

 

  1. 建立索引

    汇集索引:

(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. 删除索引:

汇集索引:

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类型,必须制定长度。

  1. 注意事项

- 避免使用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操做。

相关文章
相关标签/搜索