⚡️什么是索引

索引相当于一本图书的目录,能够快速地让你查找到书中你想看的内容。MySQL官方文档对索引的定义为:

索引(Index)是帮助MySQL高效获取数据的数据结构。

我们可以简单理解为:快速查找排好序的一种数据结构。
官方文档也提及在500~800w记录左右MYSQL的性能,所以大数据量建立索引是非常有必要的。

🎐索引的优缺点

优点:

  1. 索引大大减小了服务器需要扫描的数据量;
  2. 索引可以帮助服务器避免排序和临时表;
  3. 索引可以将随机IO变成顺序IO;
  4. 索引对于InnoDB存储引擎(对索引支持行级锁)非常重要,因为它可以让查询锁更少的元组。

缺点:

  1. 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存索引文件;
  2. 建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索引,索引文件的会膨胀很快;
  3. 如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果;
  4. 对于非常小的表,大部分情况下简单的全表扫描更高效。

🔧索引B+树数据结构

索引的类型一共有四种,B+树索引、Hash索引、全文索引和R树索引。

常用的是B+树索引和Hash索引。

Hash索引查询单条数据的时候快,但是范围查询慢。

B+树则十分适和范围查询,InnoDB存储引擎索引默认使用的就是B+树。

这里说一说mysql为什么使用B+ Tree索引,不使用B- Tree索引?

Mysql是用磁盘IO次数衡量查询效率的。一般来说索引非常大,尤其是关系性数据库这种数据量大的索引能达到亿级别,所以为了减少内存的占用,索引也会被存储在磁盘上。B-树/B+树 的特点就是每层节点数目非常多,层数很少,目的就是为了减少磁盘IO次数,但是B-树的每个节点都有data域(指针),这无疑增大了节点大小,说白了增加了磁盘IO次数(磁盘IO一次读出的数据量大小是固定的,单个数据变大,每次读出的就少,IO次数增多,一次IO多耗时),而B+树除了叶子节点其它节点并不存储数据,节点小,磁盘IO次数就少。

索引的分类

  • 普通索引index :加速查找
  • 唯一索引
  • 主键索引:primary key :加速查找+约束(不为空且唯一)
  • 唯一索引:unique:加速查找+约束 (唯一)
  • 联合索引
  • primary key(id,name):联合主键索引
  • unique(id,name):联合唯一索引
  • index(id,name):联合普通索引
  • 全文索引fulltext :用于搜索很长一篇文章的时候,效果最好。
  • 空间索引spatial :没接触过

☀️索引的注意事项

  1. 索引越多越好?
    大多数情况下索引能大幅度提高查询效率,但是数据的变更(增删改)都需要维护索引(更新表时,MySQL不仅要保存数据,还要保存索引文件),因此更多的索引意味着更多的维护成本,更多的索引意味着也需要更多的空间。
  2. 索引的字段类型问题
    text类型,也可建索引(需指定长度)
    myisam存储引擎索引键长度综合不能超过1000字节
    用来筛选的值尽量保持和索引列同样的数据类型
  3. like 不能用索引?
    尽量减少like,但不是绝对不可用,“xxxx%” 是可以用到索引的,但是”%xxx”则不可以.
    除了like,以下操作符也可用到索引:
    <,<=,=,>,>=,BETWEEN,IN
    <>,not in ,!=则不行
  4. 什么样的字段不适合建索引?
    一般来说,列的值唯一性太小(如性别,类型什么的),不适合建索引(怎样叫太小?一半说来,同值的数据超过表的百分之15,那就没必要建索引了)。
    太长的列,可以选择只建立部分索引,(如:只取前十位做索引)
    更新非常频繁的数据不适宜建索引
  5. 一次查询能用多个索引吗?
    不能。
  6. 多列查询该如何建索引?
    这里涉及两个知识点:最左前缀left-prefix,列基数cardinality
    ①按索引的最左边前缀(leftmost prefix of the index)来进行查询:
    1)查询必须从索引的最左边的列开始,否则无法使用索引。例如,你不能直接利用索引查找在某一天出生的人。
    2)不能跳过某一索引列。例如,你不能利用索引查找last name为Smith且出生于某一天的人。
    3)存储引擎不能使用索引中范围条件右边的列。例如,如果你的查询语句为WHERE last_name=“Smith” AND first_name LIKE ‘J%’ AND dob=‘1976-12-23’,则该查询只会使用索引中的前两列,因为LIKE是范围查询。
    ②列基数,是指它所容纳的所有非重复值的个数,可以理解为 distinct(某列)后的结果
    比如某个列包含值1,3,7,4,7,3,那么它的基数就是4了
    列基数越大,重复值越少,需要建索引,因为如果某列的值都是重复的就没必要建索引了。
  7. 多列查询该如何建索引
    一次查询只能用到一个索引,这里要考虑最左边前缀,所以不建议 a,b各列建索引方案。那么a还是b? 谁的区分度更高(同值的最少)就建哪个。当然,联合索引也是个不错的方案,ab,还是ba。
  8. 哪些常见情况不能用索引?
    like “%xxx”
    not in , !=
  9. 覆盖索引(Covering Indexes)拥有更高效率
    索引包含了所需的全部值的话,就只select 他们,换言之,只select 需要用到的字段,如无必要,可尽量避免select *
  10. NULL 的问题
    NULL会导致索引形同虚设,所以在设计表结构时应避免NULL 的存在

💨总结

合理使用索引能大大加快MySQL数据库的查询速度,但同时也要注意索引使用的场景和方法。