1. 概念

MySQL 官方对索引的定义为:索引(Index)是帮助MySQL 高效获取数据的数据结构。可以得到索引的本质:索引是数据结构。可以简单理解为排好序的快速查找数据结构。

1.1优缺点

优势:

  • 提高数据检索的效率,降低数据库的IO成本。
  • 通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗。

劣势:

  • 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息。
  • 实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,所以索引列也是要占用空间的。

    2. b树和b+树

    2.1两者区别

    1)B-树的关键字和记录是放在一起的;B+树的非叶子节点中只有关键字和指向下一个节点的索引,记录只放在叶子节点中。
    2)在B-树中,越靠近根节点的记录查找时间越快,只要找到关键字即可确定记录的存在;而B+树中每个记录的查找时间基本是一样的,都需要从根节点走到叶子节点,而且在叶子节点中还要再比较关键字。从这个角度看B-树的性能好像要比B+树好,而在实际应用中却是B+树的性能要好些。因为B+树的非叶子节点不存放实际的数据,这样每个节点可容纳的元素个数比B-树多,树高比B-树小,这样带来的好处是减少磁盘访问次数。尽管B+树找到一个记录所需的比较次数要比B-树多,但是一次磁盘访问的时间相当于成百上千次内存比较的时间,因此实际中B+树的性能可能还会好些,而且B+树的叶子节点使用指针连接在一起,方便顺序遍历(例如查看一个目录下的所有文件,一个表中的所有记录等),这也是很多数据库和文件系统使用B+树的缘故。

    2.2 为什么说B+树比B-树更适合实际应用中操作系统的文件索引和数据库索引?

    1) B+树的磁盘读写代价更低,B+树的内部结点并没有指向关键字具体信息的指针。因此其内部结点相对B 树更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO 读写次数也就降低了。
    2) B+树的查询效率更加稳定由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当

    2.3 聚簇索引和非聚簇索引

    聚簇索引并不是一种单独的索引类型,而是一种数据存储方式。术语‘聚簇’表示数据行和相邻的键值聚簇的存储在一起。如下图,左侧的索引就是聚簇索引,因为数据行在磁盘的排列和索引排序保持一致。
    image.png
    聚簇索引的好处:
    按照聚簇索引排列顺序,查询显示一定范围数据的时候,由于数据都是紧密相连,数据库不用从多个数据块中提取数据,所以节省了大量的io 操作。
    聚簇索引的限制:
    对于mysql 数据库目前只有innodb 数据引擎支持聚簇索引,而Myisam 并不支持聚簇索引。
    由于数据物理存储排序方式只能有一种,所以每个Mysql 的表只能有一个聚簇索引。一般情况下就是该表的主键。
    为了充分利用聚簇索引的聚簇的特性,所以innodb 表的主键列尽量选用有序的顺序id,而不建议用无序的id,比如uuid 这种。

    3. Mysql 索引分类

    3.1 单值索引

    概念:即一个索引只包含单个列,一个表可以有多个单列索引
    语法:

    1. 所表一起创建:
    2. CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name
    3. VARCHAR(200),
    4. PRIMARY KEY(id),
    5. KEY (customer_name)
    6. );
    7. 单独建单值索引:
    8. CREATE INDEX idx_customer_name ON customer(customer_name);

    3.2 唯一索引

    概念:索引列的值必须唯一,但允许有空值

    1. 随表一起创建:
    2. CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name
    3. VARCHAR(200),
    4. PRIMARY KEY(id),
    5. KEY (customer_name),
    6. UNIQUE (customer_no)
    7. );
    8. 单独建唯一索引:
    9. CREATE UNIQUE INDEX idx_customer_no ON customer(customer_no);

    3.3 主键索引

    概念:设定为主键后数据库会自动建立索引,innodb为聚簇索引

    1. 随表一起建索引
    2. CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name
    3. VARCHAR(200),
    4. PRIMARY KEY(id)
    5. );
    6. 单独建主键索引:
    7. ALTER TABLE customer add PRIMARY KEY customer(customer_no);
    8. 删除建主键索引:
    9. ALTER TABLE customer drop PRIMARY KEY ;
    10. 修改建主键索引:
    11. 必须先删除掉(drop)原索引,再新建(add)索引

    3.4 复合索引

    1、概念:即一个索引包含多个列
    复合索引在数据库操作期间所需的开销更小,可以代替多个单一索引;
    同时有两个概念叫做窄索引宽索引,窄索引是指索引列为1-2列的索引,宽索引也就是索引列超过2列的索引;
    设计索引的一个重要原则就是能用窄索引不用宽索引,因为窄索引往往比组合索引更有效;

    1. 随表一起建索引:
    2. CREATE TABLE customer (id INT(10) UNSIGNED AUTO_INCREMENT ,customer_no VARCHAR(200),customer_name
    3. VARCHAR(200),
    4. PRIMARY KEY(id),
    5. KEY (customer_name),
    6. UNIQUE (customer_name),
    7. KEY (customer_no,customer_name)
    8. );
    9. 单独建索引:
    10. CREATE INDEX idx_no_name ON customer(customer_no,customer_name);

    2、使用:
    创建复合索引 :

    1. CREATE INDEX columnId ON table1(col1,col2,col3) ;

    查询语句:

    1. select * from table1 where col1= A and col2= B and col3 = C

    这时候查询优化器,不在扫描表了,而是直接的从索引中拿数据,因为索引中有这些数据,这叫覆盖式查询,这样的查询速度非常快;
    3、注意事项

    1. ![](https://cdn.nlark.com/yuque/0/2021/png/12813714/1622273220163-e313b79e-1260-4fbc-955d-64213273d17d.png#align=left&display=inline&height=393&margin=%5Bobject%20Object%5D&originHeight=393&originWidth=436&size=0&status=done&style=none&width=436)<br />1、对于复合索引,在查询使用时,最好将条件顺序按找索引的顺序,这样效率最高;
    1. select * from table1 where col1=A AND col2=B AND col3=D

    如果使用

    1. where col2=B AND col1=A

    或者

    1. where col2=B

    将不会使用索引。

    3.5 基本语法

    image.png

    4.索引的创建时机

    4.1 适合创建索引的情况

  • 主键自动建立唯一索引;

  • 频繁作为查询条件的字段应该创建索引
  • 查询中与其它表关联的字段,外键关系建立索引
  • 单键/组合索引的选择问题, 组合索引性价比更高
  • 查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度
  • 查询中统计或者分组字段

    4.2 不适合创建索引的情况

  • 表记录太少

  • 经常增删改的表或者字段
  • Where 条件里用不到的字段不创建索引
  • 过滤性不好的不适合建索引