mysql——索引

2018-09-25  本文已影响0人  kindol

先来看个问题

假设现在有100000条从0到10000且从大到小排列的整型数据,1条数据的大小假设(真的只是假设)是1KB,操作系统的每次I/O数据块(页)大小是8KB。如果现在我要查找其中 50001 这个数据值,有如下几个方式:

  1. 最蠢的方式,遍历,每次遍历到一个值,就用这个值跟目标值做对比,如果不等于那么查找下一个。这样的话那么每次I/O是8条数据,目标数据在50001/8 约6600多次I/O 才能找到目标数据。
  2. 二分查找,最好一次性将100000条数据全部读到内存,这样查找也是很快的。

但是即使二分查找很快,但这些数据也不能单单通过一次I/O全部进入内存,进行运算。

那么怎样在I/O块大小的限制下快速利用二分查找找到目标值呢?我们得引入新的数据结构,B+树正好可以解决上述I/O块大小的限制,解决限制不是说增大了限制范围,而是我们在此限制上改变了数据的存储结构,即在同等限制条件下,快速检索到目标数据,下面讲解下B+ Tree

image

上图中:

  1. 图上蓝色的块为关键字,我们发现所有的关键字最终都会被包含在叶子节点当中。图上的黄色区块表示的是子树的指针域,比如根节点下的P2指向的就是28-65之间的索引。
  2. 所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大的顺序链接。(而B树的叶子节点并没有包括全部需要查找的信息)
  3. 所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字。(而B树的非终节点也包含需要查找的有效信息)

因此:数据 60 的 查找过程如下

  1. I/O第一次:读入5、28、65数据块,在此同级别节点块上,60在28到65之间(其实是二分查找),那走P2指针指向的子树。
  2. I/O第二次:读入28、35、56数据块,在此同级别节点块上,60大于56,所以走P3指针指向的子树(上图中就是叶子节点)。
  3. I/O第三次:读入叶子节点,在这个叶子节点中,使用二分查找算法找到目标值60。

预备知识

InnoDB中,各个数据页之间组成一个双向链表(页之间未必连续,所以是链表),而每个数据页内的记录又组成一个单向链表每个数据页都会为存储在它里边儿的记录生成一个页目录在通过主键查找某条记录的时候可以在页目录中使用二分法快速定位到对应的槽,然后再遍历该槽对应分组中的记录即可快速找到指定的记录

image

概述

索引是在存储引擎中实现的,也就是说不通存储引擎,会使用不同的索引。

索引优化也是mysql中的一种优化方式,mysql索引的四种类型:

索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录

四种索引

mysql索引的两种结构

IndexType.jpg

ps:

另一种分类方式(另一篇文章细讲)

InnoDB主键使用的是聚簇索引,MyISAM不管是主键索引,还是二级索引使用的都是非聚簇索引。

image

聚簇索引的优点:

  1. 当你需要取出一定范围内的数据时,用聚簇索引也比用非聚簇索引好。
  2. 当通过聚簇索引查找目标数据时理论上比非聚簇索引要快,因为非聚簇索引定位到对应主键时还要多一次目标记录寻址,即多一次I/O

聚簇索引的缺点:

  1. 插入速度严重依赖于插入顺序,按照主键的顺序插入是最快的方式,否则将会出现页分裂,严重影响性能。因此,对于InnoDB表,我们一般都会定义一个自增的ID列为主键(不懂!!!)。
  2. 更新主键的代价很高,因为将会导致被更新的行移动。因此,对于InnoDB表,我们一般定义主键为不可更新。
  3. 二级索引访问需要两次索引查找,第一次找到主键值,第二次根据主键值找到行数据。二级索引的叶节点存储的是主键值,而不是行指针(非聚簇索引存储的是指针或者说是地址),这是为了减少当出现行移动或数据页分裂时二级索引的维护工作,但会让二级索引占用更多的空间。
  4. 采用聚簇索引插入新值比采用非聚簇索引插入新值的速度要慢很多,因为插入要保证主键不能重复,判断主键不能重复,采用的方式在不同的索引下面会有很大的性能差距,聚簇索引遍历所有的叶子节点,非聚簇索引也判断所有的叶子节点,但是聚簇索引的叶子节点除了带有主键还有记录值,记录的大小往往比主键要大的多。这样就会导致聚簇索引在判定新记录携带的主键是否重复时进行昂贵的I/O代价。

索引的扫描方式

一些要注意的

  1. 唯一索引与唯一约束

    mysql中貌似唯一约束就是唯一索引,并没有什么不同,可能叫法不同,在sqlserver中区分还是挺明确的。

    博客中的一句话说的很在理,你为了做到数据不能有重复值,但是数据库怎么保证没有重复值呢?当然是在存储数据的时候查一遍,那么怎样查找快呢? 当然是创建索引,所以,在创建唯一约束的时候就创建了唯一索引。这可能也是mysql的一个优化机制

  2. MySQL只对<,<=,=,>,>=(!=不走索引),BETWEEN,IN,以及某些时候的LIKE才会使用索引(在以通配符%和_开头作查询时,MySQL不会使用索引)

  3. 添加索引的时候,可以不写index

索引的代价

  1. 空间耗费
  2. 在使用DML语言对表格进行修改的时候,同时需要修改索引,降低效率
  3. 如果该字段没有限制非空的话,存在插入NULL值的情况,此时,唯一索引并不起作用,也就是你可以插入n条该字段为null的数据
  4. 如果插入空字符串的话, 例如 ‘’ 、‘ ’
    不管中间是多少个空字符串在插入的时候都算作‘’,即,空串不论多长,只能插入一条。

在哪些字段上使用索引

选择索引的数据类型

MySQL支持很多数据类型,选择数据类型建立索引遵循一些规则:

选择主键类型

索引的操作

查看

show index from 'table_name';

删除

alter table 'table_name' drop index 'index_name';

drop index index_name on table_name;

添加主键索引:指定主键即可

添加唯一索引、普通索引、复合索引、复合前缀索引(也可以复合单列索引,只要后面添加数字即可)

alter table 'table_name' add index index_name (column_name[, column_name[, column_name(10)]])
上一篇 下一篇

猜你喜欢

热点阅读