# 理解MYSQL底层索引

看了很多关于索引的博客，讲的大同小异。但是始终没有让我明白关于索引的一些概念，如B-Tree索引，Hash索引，唯一索引....或许有很多人和我一样，没搞清楚概念就开始研究B-Tree，B+Tree等结构，导致在面试的时候答非所问！

**索引是什么?**

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

**索引能干什么?**

提高数据查询的效率。

索引：排好序的快速查找数据结构！索引会影响where后面的查找，和order by 后面的排序。

## 一、索引的分类 <a href="#yi-suo-yin-de-fen-lei" id="yi-suo-yin-de-fen-lei"></a>

1. 从存储结构上来划分：BTree索引（B-Tree或B+Tree索引），Hash索引，full-index全文索引，R-Tree索引。
2. 从应用层次来分：普通索引，唯一索引，复合索引、全文索引、空间索引
3. 根据中数据的物理顺序与键值的逻辑（索引）顺序关系：聚集索引，非聚集索引。

> 说明：
>
> 1️.中所描述的是索引存储时保存的形式
>
> 2️.是索引使用过程中进行的分类，两者是不同层次上的划分。不过平时讲的索引类型一般是指在应用层次的划分。

​

就像手机分类：安卓手机，IOS手机 与 华为手机，苹果手机，OPPO手机一样。

**普通索引**：即一个索引只包含单个列，一个表可以有多个单列索引

**唯一索引**：索引列的值必须唯一，但允许有空值

**复合索引**：即一个索引包含多个列

**聚簇索引(聚集索引)：**&#x5E76;不是一种单独的索引类型，而是一种数据存储方式。具体细节取决于不同的实现，InnoDB的聚簇索引其实就是在同一个结构中保存了B-Tree索引(技术上来说是B+Tree)和数据行。

**非聚簇索引：**&#x4E0D;是聚簇索引，就是非聚簇索引。

**全文索引：**&#x53EA;能在CHAR,VARCHAR,TEXT类型字段上使用全文索引，介绍了要求，说说什么是全文索引，就是在一堆文字中，通过其中的某个关键字等，就能找到该字段所属的记录行，比如有"你是个大煞笔，二货 ..." 通过大煞笔，可能就可以找到该条记录。这里说的是可能，因为全文索引的使用涉及了很多细节，我们只需要知道这个大概意思。

## 二、索引的底层实现 <a href="#er-suo-yin-de-di-ceng-shi-xian" id="er-suo-yin-de-di-ceng-shi-xian"></a>

```
mysql默认存储引擎innodb只显式支持B-Tree( 从技术上来说是B+Tree)索引，对于频繁访问的表，
innodb会透明建立自适应hash索引，即在B树索引基础上建立hash索引，可以显著提高查找效率，对于客户端是透明的，不可控制的，隐式的。
```

**Hash索引**

基于哈希表实现，只有精确匹配索引所有列的查询才有效，对于每一行数据，存储引擎都会对所有的索引列计算一个哈希码（hash code），并且Hash索引将所有的哈希码存储在索引中，同时在索引表中保存指向每个数据行的指针。

**B-Tree索引（MySQL使用B+Tree）**

​ B-Tree能加快数据的访问速度，因为存储引擎不再需要进行全表扫描来获取数据，数据分布在各个节点之中。

**B+Tree**索引

​ 是B-Tree的改进版本，同时也是数据库索引索引所采用的存储结构。数据都在叶子节点上，并且增加了顺序访问指针，每个叶子节点都指向相邻的叶子节点的地址。相比B-Tree来说，进行范围查找时只需要查找两个节点，进行遍历即可。而B-Tree需要获取所有节点，相比之下B+Tree效率更高。

> 结合存储引擎来讨论（一般默认使用B+Tree）

## 三、问题 <a href="#san-wen-ti" id="san-wen-ti"></a>

**问：为什么索引结构默认使用B-Tree，而不是hash，二叉树，红黑树？**

hash：虽然可以快速定位，但是没有顺序，IO复杂度高。

二叉树：树的高度不均匀，不能自平衡，查找效率跟数据有关（树的高度），并且IO代价高。

红黑树：树的高度随着数据量增加而增加，IO代价高。

**问：为什么官方建议使用自增长主键作为索引。**

结合B+Tree的特点，自增主键是连续的，在插入过程中尽量减少页分裂，即使要进行页分裂，也只会分裂很少一部分。并且能减少数据的移动，每次插入都是插入到最后。总之就是减少分裂和移动的频率。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tuonioooo-notebook.gitbook.io/performance-optimization/sqlyou-hua-pian/mysqlyou-hua-pian/li-jie-mysql-di-ceng-b-+-tree-de-ji-zhi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
