MySQL索引和其底层数据结构介绍
索引在项目中非常常见,它是一种帮助MySQL高效获取数据的数据结构,主要用来提高数据检索效率,降低数据库的I/O成本。同时,索引列可以对数据进行排序,降低数据排序的成本,也能减少CPU的消耗。就像是书的目录,能帮助读者快速找到所需内容。
下面从索引的类型、优缺点、创建和使用等方面详细介绍:
- 索引类型
- 普通索引:最基本的索引类型,没有唯一性限制。它可以加速对数据的查询操作。在MySQL中,使用
CREATE INDEX
语句创建普通索引,例如:CREATE INDEX idx_name ON table_name (column_name);
,这就在table_name
表的column_name
列上创建了名为idx_name
的普通索引。 - 唯一索引:该索引要求索引列的值必须唯一,但允许有空值。创建唯一索引可以确保数据的唯一性约束。创建语句如:
CREATE UNIQUE INDEX idx_unique ON table_name (column_name);
。 - 主键索引:特殊的唯一索引,用于唯一标识表中的每一行记录,不允许有空值。在创建表时,可以指定主键索引,例如:
CREATE TABLE table_name (id INT PRIMARY KEY, column1 VARCHAR(255));
,这里的id
列就是主键索引。 - 全文索引:主要用于在文本类型的列中进行全文搜索。MySQL的全文索引支持InnoDB和MyISAM存储引擎。例如:
CREATE FULLTEXT INDEX idx_fulltext ON table_name (text_column);
,在table_name
表的text_column
列上创建全文索引。不过,全文索引的使用场景相对较少,且性能优化需要谨慎处理。 - 组合索引:也叫复合索引,是在多个列上创建的索引。使用组合索引时,需要注意列的顺序,遵循最左前缀原则。例如:
CREATE INDEX idx_multiple ON table_name (column1, column2, column3);
,这是在table_name
表的column1
、column2
和column3
列上创建的组合索引。在查询时,如果条件包含column1
,或者同时包含column1
和column2
等,该组合索引都可能被使用。
- 普通索引:最基本的索引类型,没有唯一性限制。它可以加速对数据的查询操作。在MySQL中,使用
- 索引的优点
- 提高查询效率:大大减少了数据库查询时需要扫描的数据量,加快数据检索速度,提升查询性能。比如在一个有大量用户数据的表中,通过对
user_id
列建立索引,根据user_id
查询用户信息时,能快速定位到对应记录,而不用全表扫描。 - 保证数据唯一性:唯一索引和主键索引能确保特定列或列组合的值在表中是唯一的,维护了数据的完整性和一致性。
- 实现表与表之间的关联:在多表关联查询时,索引可以加快表之间的连接速度。外键约束通常借助索引来提高查询性能,使得关联查询更加高效。
- 提高查询效率:大大减少了数据库查询时需要扫描的数据量,加快数据检索速度,提升查询性能。比如在一个有大量用户数据的表中,通过对
- 索引的缺点
- 占用存储空间:索引本身需要占用一定的磁盘空间,随着数据量的增加,索引占用的空间也会增大。在高并发写入场景下,索引维护会产生额外的I/O开销,影响写入性能。
- 影响更新性能:当对表中的数据进行插入、更新或删除操作时,数据库不仅要更新数据本身,还要更新相应的索引,这会增加操作的时间成本,降低数据更新的效率。
- 索引的创建原则
- 选择合适的列:在经常用于查询条件、排序、连接操作的列上创建索引。例如,在
WHERE
子句、ORDER BY
子句、JOIN
操作涉及的列上。 - 避免过度索引:创建过多索引会增加存储和维护成本,降低写入性能。只有在必要的情况下才创建索引,权衡查询和更新操作的性能。
- 注意列顺序(组合索引):对于组合索引,将选择性高(基数大,即列中不同值的数量多)的列放在前面,遵循最左前缀原则,以提高索引的使用效率。
- 选择合适的列:在经常用于查询条件、排序、连接操作的列上创建索引。例如,在
- 查看和删除索引
- 查看索引:可以使用
SHOW INDEX FROM table_name;
语句查看指定表上的索引信息,包括索引名称、索引类型、涉及的列等。 - 删除索引:使用
DROP INDEX index_name ON table_name;
语句删除指定表上的索引。在删除索引时要谨慎,确保不会对查询性能产生负面影响。
- 查看索引:可以使用
MySQL索引的底层主要使用了B-Tree(B树)、B+Tree(B+树)和哈希表(Hash)这几种数据结构,不同的存储引擎支持的索引结构有所不同,以下是详细介绍:
B-Tree(B树)
- 结构特点
- B树是一种自平衡的多路搜索树,它的每个节点可以有多个子节点。每个节点包含多个键值和指向子节点的指针。
- 所有叶子节点位于同一层,这保证了查询的稳定性,无论查找哪个键值,所需的磁盘I/O次数大致相同。
- 节点中的键值按升序排列,左子树的所有键值小于当前节点的键值,右子树的所有键值大于当前节点的键值。
- 在MySQL中的应用
- 早期的MyISAM存储引擎在实现索引时采用过B树结构。在B树索引中,每个节点既存储键值,也存储对应的数据记录指针。
- 当进行范围查询时,B树需要在多个节点之间进行遍历,可能会涉及较多的磁盘I/O操作,效率相对较低。
B+Tree(B+树)
- 结构特点
- B+树是B树的一种变体,同样是自平衡的多路搜索树。它的非叶子节点只存储键值和指向子节点的指针,不存储数据记录指针;而叶子节点存储了所有的数据记录指针,并且叶子节点之间通过指针相连,形成一个有序链表。
- 所有的数据查询最终都要访问到叶子节点,因此查询的时间复杂度是固定的,为O(log n),其中n是节点数量。
- 在MySQL中的应用
- InnoDB和MyISAM存储引擎主要使用B+树作为索引的底层数据结构。在InnoDB中,主键索引(聚簇索引)的叶子节点存储了完整的数据记录,而辅助索引的叶子节点存储的是主键值,通过主键值再去主键索引中查找完整数据。
- 由于B+树的叶子节点之间有指针相连,非常适合范围查询。在进行范围查询时,可以沿着叶子节点的链表顺序访问,减少了磁盘I/O次数,提高了查询效率。
B树和B+树的主要区别在于
B树的非叶子节点和叶子节点都存放数据,而B+树的所有数据只出现在叶子节点,这使得B+树在查询时效率更稳定。
B+树在进行范围查询时效率更高,因为所有数据都在叶子节点,并且叶子节点之间形成了双向链表。
哈希表(Hash)
- 结构特点
- 哈希表是一种根据键值直接访问内存存储位置的数据结构,通过哈希函数将键值映射到一个固定大小的数组索引上。
- 哈希表的查找、插入和删除操作的平均时间复杂度为O(1),效率非常高。
- 在MySQL中的应用
- Memory存储引擎支持哈希索引。哈希索引适用于等值查询,例如
WHERE column = value
这种类型的查询。 - 哈希索引的缺点是不支持范围查询,因为哈希函数将键值映射到不同的位置,无法直接根据键值的大小关系进行范围查找。同时,哈希冲突的处理会增加额外的开销。
- Memory存储引擎支持哈希索引。哈希索引适用于等值查询,例如
综上所述,B+树由于其适合范围查询和有序遍历的特点,成为了MySQL中最常用的索引底层数据结构,而哈希索引则在特定的等值查询场景中发挥作用。
其他索引相关问题:
什么是聚簇索引什么是非聚簇索引?
聚簇索引是指数据与索引放在一起,B+树的叶子节点保存了整行数据,通常只有一个聚簇索引,一般是由主键构成。
非聚簇索引则是数据与索引分开存储,B+树的叶子节点保存的是主键值,可以有多个非聚簇索引,通常我们自定义的索引都是非聚簇索引。
什么是回表查询吗?
回表查询是指通过二级索引找到对应的主键值,然后再通过主键值查询聚簇索引中对应的整行数据的过程。
什么叫覆盖索引吗?
覆盖索引是指在SELECT查询中,返回的列全部能在索引中找到,避免了回表查询,提高了性能。使用覆盖索引可以减少对主键索引的查询次数,提高查询效率。
MySQL超大分页怎么处理?
超大分页通常发生在数据量大的情况下,使用LIMIT分页查询且需要排序时效率较低。可以通过覆盖索引和子查询来解决。首先查询数据的ID字段进行分页,然后根据ID列表用子查询来过滤只查询这些ID的数据,因为查询ID时使用的是覆盖索引,所以效率可以提升。
索引创建原则有哪些?
创建索引的原则包括:
表中的数据量超过10万以上时考虑创建索引。
选择查询频繁的字段作为索引,如查询条件、排序字段或分组字段。
尽量使用复合索引,覆盖SQL的返回值。
如果字段区分度不高,可以将其放在组合索引的后面。
对于内容较长的字段,考虑使用前缀索引。
控制索引数量,因为索引虽然可以提高查询速度,但也会影响插入、更新的速度。
什么情况下索引会失效?
索引可能在以下情况下失效:
没有遵循最左匹配原则。
使用了模糊查询且%号在前面。
在索引字段上进行了运算或类型转换。
使用了复合索引但在中间使用了范围查询,导致右边的条件索引失效。