索引就好比书籍的目录,能够快速指引我们找到特定内容的位置。在数据库中建立索引的目的是为了迅速定位特定值和字段,因为如果没有索引,数据库就得从头到尾逐行扫描整个表,直到找到符合条件的数据。随着表中数据量的增加,这种扫描方式会变得越来越慢
,效率会受到明显的影响,索引其实就相当于字典中的目录。
B+tree索引: 使用B+树结构进行组织,适用于范围查询和排序操作,常见于许多关系型数据库系统。典型使用场景包括:
Hash索引: 使用哈希函数进行索引,适用于等值查询,但不支持范围查询和排序,常见于一些内存数据库和某些 NoSQL 数据库。典型使用场景包括:
Full-text索引: 用于全文搜索,支持对文本内容进行搜索,通常在文本搜索引擎或支持全文搜索的数据库中使用。典型使用场景包括:
在设计数据库时,选择适当的索引类型要考虑查询的需求。如果经常进行范围查询或排序,B+tree索引是较好的选择;如果主要进行等值查询,Hash索引可能更合适;而全文搜索场景则需要使用Full-text索引来提高检索效率。
聚簇索引的叶子节点存储的是数据,而非聚簇索引存储的是数据的地址
InnoDB表要求必须有聚簇索引,默认在主键字段上建立聚簇索引
,在没有主键字段的情况下,表的第一个非空的唯一索引将被建立为聚簇索引,在前两者都没有的情况下,InnoDB将自动生成一个隐式的自增id列,并在此列上建立聚簇索引。以MyISAM为存储引擎的表不存在聚簇索引。MyISAM表中的主键索引和非主键索引的结构是一样的,索引的叶子节点不存储表数据,存放的是表数据的地址。所以,MyISAM表可以没有主键。
MyISAM表的数据和索引是分开存储的。MyISAM表的主键索引和非主键索引的区别仅在于主键索引的B+tree上的key必须符合主键的限制,非主键索引B+tree上的key只要符合相应字段的特性就可以了
InnoDB 的B+ 树叶子节点均为数据页,存放的是用户记录。因此,所有的用户记录都存放在叶子节点上
所有叶子节点组成一个双向链表,节点之间按照 row_id 升序排列
所有的非叶子节点都是索引页,存放的记录为索引记录,同样一层的节点按照 row_id 升序排列为双向链表
这整个 B+ 树就叫做索引,此外,由于它是根据主键排序的,并且存放了所有的用户记录,这个索引又被称为聚簇索引(或者叫主键索引)。
InnoDB 的每一张表都会有这样一个聚簇索引存在,它是自动创建的。有了聚簇索引,我们能很方便的根据主键来查找数据。
由于聚簇索引是按照主键 row_id 作为排序基准的,但某些场景下,我们需要对非主键列进行查询,此时就需要二级索引了
。
在选择索引类型时,考虑到物理存储的特性对查询和维护操作的影响是很重要的。聚簇索引适用于需要频繁进行范围查询和排序的场景,而辅助索引则更适用于非主键列的检索和避免主键变更的开销。
索引包括主键索引、唯一索引、普通索引和前缀索引。下面是对这些索引的简要解释:
主键索引(Primary Key Index):
唯一索引(Unique Index):
普通索引(Non-Unique Index):
前缀索引(Prefix Index):
按「字段特性」分类的这些索引种类提供了在数据库设计中更灵活的选择,可以根据具体的需求和业务场景来选择适当的索引类型。
按「字段个数」分类的索引包括单列索引和联合索引。以下是对这两种索引的简要解释:
单列索引(Single-Column Index):
特点: 只涉及一个列的索引。
适用场景: 适用于对单个列进行频繁搜索和过滤的情况,提高特定列的查询效率。
联合索引(Composite Index):
特点: 涉及多个列的组合索引,即在多个列上建立的索引。
适用场景: 适用于经常以多个列的组合作为查询条件的情况,可以加速这类联合条件的查询。
按「字段个数」分类的这两种索引类型允许数据库设计人员更灵活地根据查询需求选择适当的索引。单列索引通常用于对单一列进行快速检索,而联合索引适用于需要同时过滤多个列的查询条件。在选择索引类型时,需要综合考虑查询频率、查询条件以及对数据修改操作的影响
回表是指在使用二级索引进行查询时,二级索引的叶子节点并不存放真实的数据,而是存储了记录的主键 row_id。因此,当通过二级索引找到目标后,需要再使用这个主键 row_id 去聚簇索引中查找真实的记录数据,这个过程被称为回表。
为什么二级索引不存放真实数据呢?
数据重复: 主键索引已经包含了所有记录,如果每个二级索引再存储一次,将会占用大量磁盘空间。
写入效率低下: 写入数据时需要更新每个副本,会导致写入效率降低。
因此,二级索引通常不存放真实数据。
举个回表的场景,假设查询语句为:
SELECT * FROM table WHERE x=10;
此时,根据列 x 的索引最终查找到目标记录的主键 row_id=18。然后使用 row_id=18 去聚簇索引里面查找用户记录,最终将各列的值返回。这个去聚簇索引的过程就是回表。
回表的性能消耗:
假设二级索引 B+树层级为 n,聚簇索引 B+树层级为 m。
访问二级索引本身就需要至少 n 次磁盘 I/O,然后回表也需要至少 m 次 I/O。
因此,一次查询的磁盘 I/O 为:m + n。
所以,发生回表时实际上会有一定的性能影响。在某些场景下,尽管 SELECT 语句中存在二级索引条件,MySQL 仍然选择了全表扫描,主要是因为优化器发现回表的成本比全表扫描还大。