浅谈sql索引

索引是什么

假如你手上有一个你公司的客户表,老板说找什么客户你就得帮他找出来。mysql

客户很少的时候,你拿着手指一行一行滑,费不了多少时间就能找到。sql

后来公司作大了,客户愈来愈多,好几页的客户,你发现,一行一行滑真的好累啊,最主要找慢了还得挨老板叼。数据库

他妈的,吃力不讨好。并发

那咋办?高并发

我相信这么聪明的你不会坐以待毙的。性能

你可能会本身作一些记录,好比拿个小本本写上,mysql索引

28岁的客户在第一页
29岁的客户在第二页指针

或者code

姓张的客户在第二页
姓李的客户在第三页和第四页blog

固然这些要根据那张客户表的实际状况来。

这样子,下次老板叫你找29岁的客户,你就一会儿翻到第二页,一会儿就找到了,轻松又漂亮地解决了问题。

这么机智地解决了问题,当上ceo,迎娶白富美就指日可待了。

好了,美好故事到此就结束了。

真实的状况是怎么样的呢?

真实的状况就是数据库就是故事中的你,你就是故事中的老板,故事中的小本本,就是我们今天要讲的索引。

索引的特色

那么从这个故事中能够看出索引有什么特色呢?

为了提升查找效率而创建

若是你不给数据库加索引的话,多数状况下,它就真的是一行行找,效率极低。

数据量少的时候不须要索引

但数据量少的时候,也不必建索引,你想一想啊,数据量少的时候,你一会儿就找到了,速度比你去翻小本本时间可能还要快点,就不要浪费一个小本本了。
MySQL的索引本质也是一张表的,创建索引也须要相应的空间。

索引是创建在表的数据上的

上面的故事里我也说了,小本本的内容要根据你表里的实际状况来的。
这样的话,若是创建了索引,就要注意两个点:

  1. 不要实际删除数据。
    假如你有批客户闹掰了,你一辈子气,把客户表中那一整页都撕了。
    那你下次按照【31岁的客户在第20页】这个规则去找,可是前面的就被你撕了,如今31岁的客户就提早了几页,你数到第20页,发现找不到,人都傻了。
    MySQL也是这样的,若是删除数据,会致使按照索引查找的数据不会在原先的位置上。

  2. 频繁更新的字段不要创建索引。
    假设用户的年龄每天变,那最好也不要记在小本本上了,不然你天天都要去更新小本本,今天是【31岁的客户在第20页】,明天就要改为【32岁的客户在第20页】了。
    MySQL也是这样的,若是创建索引的字段频繁更新,这样便会致使以前创建的索引须要频繁更新。

MySQL索引分类

人家MySQL创建索引的方式比咱们记小本本的方式要聪明有效率地多了。
你能够看到我上面作小本本的方式都是根据表中的某一列来的,好比

【31岁的客户在第20页】这个是根据客户的年龄这一列来作的;
【姓李的客户在第三页和第四页】这个使用客户的名字这一列来作的。

在MySQL中,咱们也只是须要告诉MySQL用哪些列来作索引便可,而后接下来的事他就会本身作。
我们创建的索引呢,根据使用列的状况不一样,能够分类以下:

  • 单值索引:即一个索引只包含单个列。一个表能够有多个单列索引。

  • 惟一索引:索引列的值必须惟一,但容许有空值。

  • 复合索引:即一个索引包含多个列。

假如如今有一个people表,内有字段id(主键不须要作索引),name,age,phone_number(电话号码)那么:

  • 单值索引:能够单独用nameage作一个索引,任何一个字段均可以。这样的索引能够作多个。
  • 惟一索引:和单值索引同样,但作索引的该字段必须惟一,好比你肯定people表中phone_number的值惟一的话,那么即可以在上面创建惟一索引。
  • 复合索引:能够用(name,age)(age,phone_number)(name,age,phone_number)作一个索引。

建议:创建复合索引,且一个表不要超过5个索引。

基本语法

  • 建立(若是加上UNIQUE则建立惟一索引):

    CREATE [UNIQUE] INDEX indexName ON mytable(columnname(length));

    ALTER mytable ADD [UNIQUE] INDEX[indexName] ON (columnname(length));

  • 删除:

    DROP INDEX [indexName] ON mytable;

  • 查看:

    SHOW INDEX FROM table\G

MySQL索引结构

上面的索引创建好后,MySQL是按照什么样的策略去查找数据的呢。
有几种结构,下面讲的是比较经常使用的BTree结构。

  • 图片介绍:

    如图一颗B+树,浅蓝色表示磁盘块,每一个磁盘块包括几个数据项(深蓝色)和指针(黄色)。

    如磁盘块1包括数据项17和35,包含指针P一、P二、P3;P1表示小于17的磁盘块,P2表示在17-35之间的磁盘块,P3表示大于35的磁盘块。

    真实的数据只存在于叶子节点,非叶子节点不存储真实数据,只存储指引搜索方向的数据项。

    如1七、35并不真实存在数据表中。

  • 查找过程(以上图查找数据项29):

    首先把磁盘块1由磁盘加载到内存,此时发生一次IO;在内存中用二分查找肯定29在17和35之间,锁定磁盘块1的P2指针,由于内存时间很是短(相比磁盘的IO)能够忽略不计。

    将磁盘块1的P2指向的磁盘块3由磁盘加载到内存,发生第二次IO;肯定29在26和30之间,指向磁盘块3的P2指针。

    将磁盘块3的P2指针指向的磁盘块8加载到内存,发生第三次IO,同时内存中作二分查找找到29。

    查询结束,总计三次IO。

  • 真实的状况是:3层的B+树能够表示上百万的数据,若是上百万的数据查找只须要3次IO,性能提升将是巨大的,若是没有索引,每一个数据项都要发生一次IO,那么总共须要上百万次IO。

  • 总结:减小IO次数能够减小查询时间,提升性能,那么怎么减小IO次数?
    答案:增长树的广度而非深度。B+树的叶子节点能够多。

创建索引的时机

哪些状况须要建立索引
  • 主键自动创建惟一索引
  • 频繁做为查询条件的字段应该建立索引
  • 查询中与其余表关联的字段,外键关系创建索引
  • 频繁更新的字段不适合建立索引 -- 由于每次更新不仅更新记录还会更新索引
  • Where里用不到的字段的不建立索引
  • 单键/组合索引的选择问题 -- 在高并发下倾向建立组合索引
  • 查询中排序的字段 -- 排序字段若经过索引去访问将大大提升排序速度
  • 查询中统计或者分组字段
哪些状况不须要建立索引
  • 表记录太少 -- mysql300w左右就能够考虑建索引了
  • 常常增删改的表 -- 由于索引要跟着更新
  • 数据重复且分布平均的表字段 -- 能够用(该字段不一样的数据的数量)/(该字段总的数据量),值越接近1,说明不怎么重复,越有建索引的价值。
相关文章
相关标签/搜索