Java面试题--MySQL索引

一. 索引介绍

MySQL的索引是一种数据结构,它可以帮助MySQL快速定位需要访问的记录。索引可类比于一本书的目录,通过它可以快速找到某个特定的记录。

MySQL支持多种类型的索引,每种索引都有其优势和局限性,常用的包括:

  • B-tree索引:B-tree索引是MySQL常用的索引类型,其优点是查询速度快,可以支持前缀查找、范围查找和排序等功能。
  • 哈希索引:哈希索引是根据索引列值的哈希函数值进行存储,比B-tree索引查询更快,但不支持范围查找。
  • 全文索引:全文索引可以支持对文本类型的列进行全文搜索,如文章内容等。
  • 空间索引:空间索引可以支持对空间类型的列进行范围查找和空间关系查询,如地理位置信息。

在创建索引时,需要考虑以下几个方面:

  1. 需要索引的列以及索引类型
  2. 索引的创建方式,如可以手动创建索引也可以通过修改特定参数自动创建
  3. 索引对性能的影响,如索引可以提高查询速度,但也会造成额外的磁盘空间和性能损失
  4. 索引的维护和更新,在修改数据时也需要同时更新索引,否则可能会导致查询结果错误。

因此,在创建索引时需要综合考虑多种因素,以提高MySQL数据库系统的性能和效率
一种能帮助mysql提高查

1.索引优点

索引是数据库中一种常用的数据结构,它可以极大地提高数据库的查询性能。主要有以下几个优点:

  1. 快速查询:索引可以帮助数据库快速定位需要访问的记录,从而快速查询数据,避免遍历整张表的操作,提高查询速度。

  2. 降低系统I/O开销:索引可以帮助减少查询时所需的I/O次数,因为当数据库需要检索数据时,它会首先在索引中进行搜索,而不是扫描整个表。

  3. 支持排序和分组:利用索引也可以很容易地支持排序和分组等操作,将结果返回给用户。

  4. 唯一性约束:使用索引还可以确保表的数据完整性,例如,使用主键索引可以确保表中每行数据的唯一性。

  5. 加速连接:数据库中常常需要进行表之间的连接操作,这个时候如果有外键设置索引,可以提高连接的速度。

综上所述,使用索引可以大大提高数据库系统的性能,降低响应时间,并增强数据的完整性和安全性。在应用程序设计中,合理地使用索引也是提高应用程序性能的重要手段之一。

2.索引缺点

索引在提升数据库查询效率和数据完整性方面具有重要意义,但同时也存在以下缺点:

  1. 增加存储空间:索引需要占用一定的存储空间,特别是当表中有多个索引时,占用的空间更大。因此,在创建索引时要权衡其对存储空间的占用。

  2. 增加更新时间:当有数据更新时,索引也需要更新,这会增加更新表格的时间。如果表中有多个索引,更新表格的时间也会相应增加。

  3. 增加查询优化困难度:选择合适的索引、调整查询顺序等,都需要一定的数据库知识和经验,因此对于初学者来说,使用索引可能会带来一些学习成本。

  4. 索引可失效:当数据库表数据量很大时,索引扫描大量数据时可能不会使用索引,导致索引失效。此时需要重新考虑是否需要建立新的索引以减少查询耗时。

  5. 索引无法覆盖所有查询:在某些情况下,如对大文本数据、二进制数据等类型的字段,索引不起作用,此时需要重新考虑索引的有效性。

综上所述,使用索引虽然可以提升数据库的性能,但不合理地使用索引也可能会对数据库性能造成不利影响(占用磁盘空间
当对表的数据进行增删改的时候,因为要维护索引,所以速度收到影响)。因此,在使用索引时应适当权衡其优缺点,按需选择使用。

得出结论:数据库表并不是索引加的越多越好,而是仅为那些常用的搜索字段建立索引效果才是最佳的!

二、索引的分类

在数据库中,根据不同的索引实现方式,可将索引主要分为以下三类:

  1. B-tree索引:B-tree索引是MySQL中最常用的索引类型之一,它是一种多级索引结构,用于对数据表中的一个或多个列创建索引,以便加快数据检索的速度。B-tree索引适用于等值查询和范围查找,对于一些模糊查询、排序等操作也能有不错的表现,常常被用作普通索引、主键和唯一索引。

  2. 哈希索引:哈希索引是一种将索引列中的值哈希化后,再将哈希值作为匹配索引列的关键字,并将记录按哈希值存储的索引结构。哈希索引适合等值匹配的单一查询,相比B-tree索引,它的查询速度更快,但是由于哈希冲突的存在,范围查询和排序需要枚举每个值来查找,所以性能相比B树要差。利用hash存储需要将文件存添加到内存,浪费内存的存储空间

  3. 全文索引:全文索引是一种针对文本类型数据的索引结构,可以支持对文本列的全文搜索。文本列经过分词处理后,再对每个单词创建索引,这样就可以在查询时快速定位到包含关键字的记录了,并按照相关度进行排序。全文索引适合于对大量文本和字符类型的数据进行高效搜索。

此外,根据数据库表中的索引数量和索引的特点,还可以将索引分类为普通索引、唯一索引、主键索引、复合索引、覆盖索引等。

普通索引

普通索引是数据库表上最基本的索引类型之一,常常用于在一个表的列上优化查询性能。普通索引基于B-tree数据结构实现,索引列的每个值都指向行数据存储位置的物理地址。

与主键索引、唯一索引不同的是,普通索引允许重复的值,一个表可以有多个普通索引。在创建普通索引时,可以选择对单个列、多个列或是表达式来建立索引。

通过对索引列进行查询,数据系统可以在索引中快速定位到对应记录,避免了全表扫描带来的查询性能瓶颈。同时,普通索引还支持一些高级查询功能,例如排序和分组等操作。

在实际使用时,应该根据具体情况选择合适的索引类型,并进行适当的优化,以提高数据库系统的性能、响应速度和安全性。普通索引是数据库系统中常见的优化方式之一,当遇到多次查询同一个表时,就应该考虑建立普通索引以优化查询性能。

唯一索引

唯一索引是一种用于确保数据库表中某些列的唯一性的索引类型。特别地,唯一索引指的是在一个表的某一列上建立的索引,保证该列中的值在整个表中都是唯一的。

与主键索引不同的是,唯一索引允许空值,即一个列可以有多行空值。在建立唯一索引时,可以通过修改表定义语句,或者使用CREATE UNIQUE INDEX语句来创建唯一索引。

唯一索引比一般索引更严格,它会强制只允许唯一的值,不会允许重复的值。这样可以确保数据的完整性和一致性,避免数据不一致的情况出现。

在实际使用过程中,建立唯一索引对于提高查询性能和确保数据的完整性都非常有帮助,建立唯一索引的列可以成为表中的主键,也可以作为外键引用其他表的信息。

需要注意的是,当建立唯一索引时需要了解表结构的完整性,合理地对索引的定义进行选择,以避免数据冗余和不必要的性能开销。

主键索引:PRIMARY KEY

设定为主键后,数据库自动建立索引,innodb为聚簇索引,主键索引列值不能有空(Null)

主键索引(Primary Key Index)是一种用于数据库管理系统中的索引类型。它是指在关系数据库中,唯一标识记录的索引,也就是每个记录唯一的标识符,用于标识数据表中的每行记录。

主键索引通常被创建在一张表的一个或者多个列上,用以保证这些列里的值唯一。关系数据库管理系统使用主键索引来加快数据访问,提高数据操作的性能以及确保数据一致性。

在创建主键时,常常要求保证主键的值不为空或唯一。主键索引除了可以用于禁止出现重复数据以外,还可以作为其它表关联的基础,以便于建立外键。因此在设计数据库的时候,主键索引的设计是非常重要的一个环节。

单值索引:又叫单列索引、普通索引

即,一个索引只包含单个列,一个表可以有多个单列索引

唯一索引:

索引列的值必须唯一,但允许有空值(Null),但只允许有一个空值(Null)
复合索引:
即,一个索引可以包含多个列,多个列共同构成一个复合索引!

eg: SELECT id (name age) INDEX WHERE name AND age;

全文索引:Full Text (MySQL5.7之前,只有MYISAM存储引擎支持全文索引)

全文索引类型为FULLTEXT,在定义索引的列上支持值的全文查找,允许在这些索引列中插入重复值和空值。全文索引可以在Char 、Varchar 上创建。

三、索引的基本操作

主键索引可以有以下几种创建方式:

  1. 使用 CREATE TABLE 命令创建表时,可以使用 PRIMARY KEY 约束定义主键。

  2. 在 CREATE TABLE 命令中,可以使用 UNIQUE 约束强制要求唯一性,并使用 NOT NULL 约束强制要求非空。这样就可以将一个或多个列定义为主键。

  3. 对于已经存在的数据库表,可以使用 ALTER TABLE 命令把特定列定义为主键。

  4. 另外,在一些数据库管理工具中,可以通过图形界面操作创建主键。

无论哪种方法,主键都要求唯一性和非空性。同时,主键索引通常会被自动创建,因为它们可以提高查询性能,这也是数据库管理系统中的一个重要优化策略。

3.1 主键索引创建

-- 建表语句:建表时,设置主键,自动创建主键索引

CREATE TABLE t_user (
	id VARCHAR(20) PRIMARY KEY,
    name VARCHAR(20)
);

-- 查看索引
SHOW INDEX FROM t_user;

在已存在的表中添加主键约束,需要使用 ALTER TABLE 命令来修改表结构,以下是添加主键索引的基本语法:

ALTER TABLE table_name
ADD CONSTRAINT constraint_name PRIMARY KEY (column1, column2, ...);

其中,table_name 是要修改的表的名称,constraint_name 是要添加的主键约束的名称,column1, column2 等是要作为主键的列的名称。

如果只需要添加一个列作为主键,可以省略括号中的列名列表,例如:

ALTER TABLE table_name
ADD CONSTRAINT constraint_name PRIMARY KEY (column1);

注意,添加主键约束时需要保证要添加为主键的列不含有 NULL 值(为 NULL 的列值不能成为主键),如果该列包含了 NULL 值,那么需要去除该列中的 NULL 值,或者使用一个 AUTO_INCREMENT 属性(自动增量,只在主键为整型时可用)来自动生成唯一的值。

另外,在一些数据库管理工具的界面上也可以方便地添加主键索引,例如在 MySQL Workbench 中,可以通过右键单击表,在“Alter Table”菜单中选择 “Add Primary Key…” 选项来添加主键索引。

3.2 单列索引创建(普通索引/单值索引)

-- 建表时创建单列索引:
-- 这种方式创建单列索引,其名称默认为字段名称:name
CREATE TABLE t_user (
	id VARCHAR(20) PRIMARY KEY,
    name VARCHAR(20)KEY(name)
);

-- 建表后创建单列索引:
-- 索引名称为:name_index 格式---> 字段名称_index
CREATE INDEX name_index ON t_user(name)

-- 删除单列索引
DROPINDEX 索引名称 ON 表名

3.3 唯一索引创建

-- 建表时创建唯一索引:
CREATE TABLE t_user2 (
	id VARCHAR(20) PRIMARY KEY,
    name VARCHAR(20),
    UNIQUE(name)
);

-- 建表后创建唯一索引:
CREATE UNIQUE INDEX name_index ON t_user2(name);

3.4 复合索引创建

-- 建表时创建复合索引:
CREATE TABLE t_user3 (
	id VARCHAR(20) PRIMARY KEY,
    name VARCHAR(20),
    age INT,
    KEY(name,age)
);

-- 建表后创建复合索引:
CREATE INDEX name_age_index ON t_user3(name,age);
-- 复合索引查询的2个原则
-- 1.最左前缀原则
-- eg: 创建复合索引时,字段的顺序为 name,age,birthday
-- 在查询时能利用上索引的查询条件为: 
SELECT * FROM t_user3 WHERE name = ?
SELECT * FROM t_user3 WHERE name = ? AND age = ?
SELECT * FROM t_user3 WHERE name = ? AND birthday = ?
SELECT * FROM t_user3 WHERE name = ? AND age = ? AND birthday = ?
-- 而其他顺序则不满足最左前缀原则:
... WHERE name = ? AND birthday = ? AND age = ? -- 不满足最左前缀原则
... WHERE name = ? AND birthday = ? -- 不满足最左前缀原则
... WHERE birthday = ? AND age = ? AND name = ? -- 不满足最左前缀原则
... WHERE age = ? AND birthday = ? -- 不满足最左前缀原则


-- 2.MySQL 引擎在执行查询时,为了更好地利用索引,在查询过程中会动态调整查询字段的顺序!
-- 这时候再来看上面不满足最左前缀原则的四种情况:
-- 不满足最左前缀原则,但经过动态调整顺序后,变为:name age birthday 可以利用复合索引!
... WHERE name = ? AND birthday = ? AND age = ? 
-- 不满足最左前缀原则,也不能动态调整(因为缺少age字段),不可以利用复合索引!
... WHERE name = ? AND birthday = ? 
-- 不满足最左前缀原则,但经过动态调整顺序后,变为:name age birthday 可以利用复合索引!
... WHERE birthday = ? AND age = ? AND name = ?
-- 不满足最左前缀原则,也不能动态调整(因为缺少name字段),不可以利用复合索引!
... WHERE age = ? AND birthday = ?

四、索引的数据结构

MySQL 中常用的索引数据结构主要有 B+Tree、Hash 等,但是 Hash 索引只能用于满足特定条件的查询,如等值比较,而 B+Tree 不仅支持等值查询,也支持范围查询、排序和分组等多种查询操作,因此 B+Tree 索引是 MySQL 中最常见的索引类型。

除了 B+Tree 索引之外,还有 Inverted List 索引、Full-Text 索引等其他类型的索引结构。Inverted List 索引常用于实现全文搜索,它记录每个单词在数据集合中出现的位置,用于支持关键词查询。Full-Text 索引也是用于全文搜索的一种索引类型。

总的来说,MySQL 中的索引数据结构主要是 B+Tree,在大型数据集的情况下,B+Tree 索引可以提高检索效率、支持范围查询和排序等操作,因此是 MySQL 中最常用和最有效的索引类型之一。

B-Tree
Java面试题--MySQL索引_第1张图片

B-Tree,也称为平衡树,是一种常用的数据索引结构。它优化了二叉搜索树的缺点,并且被广泛地应用于数据库和文件系统等需要访问大量数据的领域。

B-Tree 的核心特性是将多个元素存储在一个节点中,并将节点存储在磁盘块中。这意味着可以通过访问少数磁盘块来访问大量节点,从而可以避免访问整个磁盘,在大量数据的情况下具有非常高的效率。另外,B-Tree 的根节点和叶子节点之间的高度是相等的,也就是说,每个节点的高度都是相同的,这样可使查询、删除和插入操作的时间复杂度都是 O(log n) 级别。

B-Tree的节点分为内部节点和叶子节点。其内部节点包含若干子节点、键列表和指向子节点的索引,键值按照升序排序。内部节点的数量定义为“阶数”,通常每个节点阶数很大,能达到数百或数千。叶子节点包含一个或多个键及其关联的数据指针或引用等,数据按照键值大小依次存放。每个叶子节点的指针指向相应的数据块或数据文件的地址。

B-Tree的实现是基于分级分组的算法,每个节点都会以磁盘块为单位进行存储,由于整个数据集很大,因此节点通常是存储在磁盘上的。对于查询节点,B-Tree使用二分查找的算法在每个节点中查找其位置,然后再沿树上节点依次查找。

总体而言,B-Tree是一种优化后的、层级式高效索引数据结构,具有易于实现、空间和时间复杂度较小等优点,适用于存储在磁盘或其他直接存储设备上的数据,常在文件系统和数据库等领域得到应用。

B+Tree
Java面试题--MySQL索引_第2张图片

MySQL 的主要索引数据结构是基于 B+Tree (B 树和 B+Tree 不同)的,这是一种树状数据结构,旨在帮助数据的快速检索。B+Tree 索引在数据库系统中广泛使用,是一种多叉树,它的每个非叶子节点都存储着一段数据。这些数据用于帮助搜索引擎快速定位包含某个键值的叶子节点。

B+Tree 索引是一种基于磁盘存储的索引结构,它的每个节点以磁盘块为单位存储,并且可以在磁盘上实现跨节点访问。具体来说,B+Tree 索引的每个节点都包含了一个指向下一个节点的指针,这种设计使得搜索引擎可以使用更少的磁盘扫描次数来找到具有特定关键字的数据记录(叶子节点)。这种索引结构的优点是支持快速查找、排序和范围查询,并是数据库系统实现高效检索的关键。

总体来说,B+Tree 索引具有以下几个优点:

  1. B+Tree 索引的搜索复杂度为 O(logN),非常适合大型数据集的检索。

  2. B+Tree 索引在范围查询和排序方面的表现也非常出色。

  3. B+Tree 索引支持部分匹配、前缀匹配和后缀匹配。

  4. 在 B+Tree 索引中进行索引记录的插入和删除操作时,树的结构可以保持平衡,从而确保检索效率高。

总之,B+Tree 索引是 MySQL 中常用的索引类型之一,它使用磁盘上的树形结构,优化了磁盘访问,从而使数据的插入和检索效率更高。

B Tree和B+Tree的区别

B-Tree 和 B+Tree 都是树状数据结构,用于帮助数据的快速检索,但它们之间也存在一些区别:

  1. 叶子节点不同:B-Tree 的每个节点都可以存储数据,因此叶子节点既存储键值,也存储数据;而 B+Tree 的所有叶子节点都只存储数据,而非键值。

  2. 内部节点的子节点数不同:B-Tree 中,每个节点可以有多个子节点,其数量通常在 2-4 个之间;而 B+Tree 子节点的数量通常在几十个到上百个之间。

  3. 高度不同:B-Tree 的高度相对较低,通常只有几层;而 B+Tree 的高度相对较高(一层叶节点到根节点需要遍历的层数更多),但可以使用更少的磁盘扫描次数来找到特定的记录,因此在大型数据集上使用更为广泛。

  4. 磁盘块使用方式不同:B-Tree 每个节点既存储键值和数据,也存储子节点的指针,因此它的节点大小通常比 B+Tree 大,占用更多的磁盘块;而 B+Tree 只存储指向子节点的指针,因此磁盘块的利用率更高。

总的来说,B+Tree 通常被认为是一种更优秀的索引结构,由于其各种优点,被广泛用于数据库管理系统和文件系统中,而 B-Tree 的优点在某些情况下也十分明显,例如少量节点时,具有更低的访问时间和更小的内存使用。

接下来我们用一个示例来详说一下B+Tree数据结构

-- 建表:
CREATE TABLE t_emp(
	id INT PRIMARY KEY,
    name VARCHAR(20),
    age INT
);

-- 插入数据:插入时,主键无序
INSERT INTO t_emp VALUES(5,'d',22);
INSERT INTO t_emp VALUES(6,'d',22);
INSERT INTO t_emp VALUES(7,'3',21);
INSERT INTO t_emp VALUES(1,'a',23);
INSERT INTO t_emp VALUES(2,'b',26);
INSERT INTO t_emp VALUES(3,'c',27);
INSERT INTO t_emp VALUES(4,'a',32);
INSERT INTO t_emp VALUES(8,'f',53);
INSERT INTO t_emp VALUES(9,'b',13);

-- 查询:自动排序,有序展示(因为主键是有主键索引的,因此会自动排序)

问题:为什么数据插入时,未按照主键顺序,而查询时却是有序的呢?

原因:
数据插入时未按照主键顺序,是因为数据通常是以随机的顺序被插入到数据库中。然而,查询时却可以是有序的,这是因为数据库管理系统 (DBMS) 在执行查询时,可以按照指定的顺序返回结果。在这种情况下,DBMS 可以使用低层次的数据结构(如 B 树或哈希表)来优化查询的性能,并快速地找到所需的数据。这些数据结构可以按照某些规则,例如主键的值大小,对数据进行有序存储和检索,因此返回的结果也会是有序的。因此,在插入数据时,不要期望数据将按照主键顺序插入数据库中。但是,在查询数据时,可以使用 ORDER BY 子句来请求按照指定的顺序返回结果。

MySQL底层为主键自动创建索引,一旦创建了索引,就会进行排序!
实际上这些数据在MySQL底层的真正存储结构变成了下面这种方式:
在这里插入图片描述

问题:为什么要排序呢?

因为排序之后查询效率就快了,比如查询 id = 3 的数据,只需要按照顺序去找即可,而如果不排序,就如同大海捞针,假如100W条数据,可能有时候需要随机查询100W次才找到这个数据,也可能运气好上来第1次就查询到了该数据,不确定性太高!

4.1 原理分析图

Java面试题--MySQL索引_第3张图片

1.InnoDB引擎每页存储数据16KB,
2.INT类型占4个字节,VARCHARI20占20个字节,指针P占8个字节

1条记录占磁盘空间大小为:
主键ND+name(VARCHAR(2O)+age(INT)+P指针 :
	4byte + 20byte + 4byte + 8byte = 36byte

数据存储层1page可以存储的记录总数为:
	16KB*1024/36byte≈455条

页目录层1个页目录数据占磁盘空间大小为:
	4+8=12byte

页目录第1页可以存的总page数为:
	16KB*1024/12byte≈1365
  • 上图这种分层树结构查询效率较高,因为如果我需要查询 id=4的数据,只需要在页目录中匹配,大于3且小于5,则去3对应的page=2中查找数据,这样就不需要从第1页开始检索数据了,大大提高了效率!

  • 从上图可得出,在只有2层的结构下,1page 可以存储记录总数为 1365 * 455 ≈ 62万条,而如果再加1层结构,来存储page层分页目录数据的分页层PAGE的话,那么1PAGE可以存储总page数为:1365 * 1365 ≈ 186万条page,而1PAGE存储的总记录数为 1365 * 1365 * 455 ≈ 8.5 亿条。因此,我们平时使用的话,2层结构就已经足够了!实际上1个页存储的总数据树可能大于理论估计的,因为VARCHAR(20)占20个字节,而实际上可能存储的数据并没有20个字节,可能更小!

5. 聚簇索引和非聚簇索引

5.1 聚簇索引和非聚簇索引分析

在表中,聚簇索引实际上就是指的是主键索引!如果表中没有主键的话,则MySQL会根据该表生成一个RoleID,拿这个RoleId当做聚簇索引!

聚簇索引:将数据存储与索引放到一起,索引结构的叶子节点保存了每行的数据。聚簇索引不一定是主键索引,但是主键索引肯定是聚簇索引!

非聚簇索引:将数据与索引分开存储,索引结构的叶子节点指向了数据对应的位置(聚簇索引的值)!非聚簇索引检索数据是在自己的 “树” 上进行查找,

在选择使用聚簇索引还是非聚簇索引时,需要考虑以下因素:

  • 数据的访问模式:如果数据经常被随机访问,那么使用聚簇索引可能更好。如果数据经常被顺序访问,那么使用非聚簇索引可能更好。
  • 数据分布:如果数据的值在索引列上高度分散,那么使用聚簇索引可能更好。如果数据的值在索引列上高度集中,那么使用非聚簇索引可能更好。
  • 数据库规模:如果数据库中的数据量非常大,那么使用非聚簇索引可能更好,因为它们可以提高插入和更新数据的性能。
  • 索引维护成本:如果维护索引的成本很高,那么使用非聚簇索引可能更好,因为它们不需要经常重新组织整个表。

主索引和辅助索引的检索过程:
Java面试题--MySQL索引_第4张图片

注意:在InnoDB中,在聚簇索引之上创建的索引称之为辅助索引,例如:复合索引、单列索引、唯一索引。一个表中只能有1个聚簇索引,而其他索引都是辅助索引!辅助索引的叶子节点存储的不再是行的物理位置,而是主键的值,辅助索引访问数据总是需要二次查找的!

非聚簇索引检索数据时,检索一次本树再去聚簇索引树中检索一次,这样二次检索树结构,那么为什么不直接在非聚簇索引树叶子节点中存放行数据物理地址,这样只需要检索一次树结构就拿到行数据呢?

之所以不在非聚簇索引树的叶子节点直接存放行数据的物理地址,是因为,存储数据的物理地址会随着数据库表的CRUD操作而不断变更,为了保证能获取到数据,这时必须要对非聚簇索引树相关叶子节点的地址进行一遍修改!而存主键,主键不会随着CRUD操作发生变化,宁愿多查一次树,也不要再修改一次树的结构!

5.2 MySQL两种引擎中的(非)聚簇索引

InnoDB中:

  • InnoDB中使用的是聚簇索引,将主键组织到一颗B+树中,而行数据就存储在该B+树的叶子节点上,若使用WHERE id = 4 这样的条件查找主键,则按照B+树的检索算法即可查找对应的叶子节点,之后获得对应的行数据!
  • 若对使用单列索引(非聚簇索引)的name字段进行搜索,则需要执行2个步骤:
    • 第一步:在辅助索引B+树中检索name,到达其对应的叶子节点后获得该字段对应行记录的主键id!
    • 第二步:使用主键id在主索引B+树中再次执行一次树的检索,最终到达对应的叶子节点并获取到行记录数据!
  • 聚簇索引默认是主键,如果表中没有定义主键,InnoDB会选择一个唯一且非空的索引代替主键作为聚簇索引。而如果也没有这样的唯一非空索引,那么InnoDB就会隐式定义一个主键(类似于Oracle中的RowId)来做为聚簇索引。
  • 如果已经设置了聚簇索引又希望再单独设置聚簇索引,则必须先删除主键,然后添加我们想要的聚簇索引,最后再恢复主键即可!

MYISAM中:

  • MYISAM使用的是非聚簇索引,非聚簇索引的两颗B+树看上去没有什么不同,节点的结构完全一致,只是存储的内容不同,主键索引B+树的节点存储了主键,辅助索引B+树存储量辅助键。

  • 表数据存储在独立的地方,这两颗B+树的叶子节点都使用一个地址指针指向真正的表数据,对于表数据来说,这两个键没有任何差别。

  • 由于索引树是独立的,通过辅助键检索无需再次检索主键索引树!

5.3 聚簇索引和非聚簇索引的优/劣势

问题:每次使用辅助索引检索都需要经过2次B+树查找,看上去聚簇索引的效率明显要低于非聚簇索引,那么聚簇索引的优势何在呢?

1.由于行数据和聚簇索引树的叶子节点存储在一起,同一页中会有多条行数据,首次访问数据页中某条行记录时,会把该数据页数据加载到Buffer(缓存器)中,当再次访问该数据页中其他记录时,不必访问磁盘而直接在内存中完成访问。

注:主键id和行数据一起被载入内存,找到对应的叶子节点就可以将行数据返回了,如果按照主键id来组织数据,获取数据效率更快!

2.辅助索引的叶子节点,存储主键的值,而不是行数据的存放地址。这样做的好处是,因为叶子节点存放的是主键值,其占据的存储空间小于存放行数据物理地址的储存空间

使用聚簇索引需要注意什么?

当使用主键为聚簇索引时,而不要使用UUID方式,因为UUID的值太过离散,不适合排序,导致索引树调整复杂度增加,消耗更多时间和资源。

建议主键最好使用INT/BIGINT类型,且为自增,这样便于排序且默认会在索引树的末尾增加主键值,对索引树的结构影响最小(下面主键自增的问题会解释原因)。而且主键占用的存储空间越大,辅助索引中保存的主键值也会跟着增大,占用空间且影响IO操作读取数据!

为什么主键通常建议使用自增id?

聚簇索引树存放数据的物理地址(xx1,xx2,xx3,xxx5)与索引顺序(1,2,3,5)是一致的,即:
1.只要索引是相邻的,那么在磁盘上索引对应的行数据存放地址也是相邻的。

2.如果主键是自增,那么当插入新数据时,只需要按照顺序在磁盘上开辟新物理地址存储新增行数据即可。

3.而如果不是主键自增,那么当新插入数据后,会对索引进行重新排序(重新调整B+树结构),磁盘上的物理存储地址也需要重新分配要存储的行数据!

什么情况下无法利用索引呢?

-- 1. 查询语句中使用LIKE关键字:(这种情况主要是针对于单列索引)
-- 在使用LIKE关键字查询时,如果匹配字符串的第一个字符为'%',则索引不会被使用,而'%'不在最左边,而是在右边,则索引会被使用到!
-- eg:
SELECT * FROM t_user WHERE name LIKE 'xx%' -- 可以利用上索引,这种情况下可以拿xx到索引树上去匹配
SELECT * FROM t_user WHERE name LIKE '%xx%' -- 不可以利用上索引
SELECT * FROM t_user WHERE name LIKE '%xx' -- 不可以利用上索引

-- 2. 查询语句中使用多列索引:(这种情况主要是针对于聚合索引)
-- 多索引是在表的多个字段创建索引,只有查询条件中使用了这些字段中的第一个字段,索引才会被使用。即:最左前缀原则,详情查看3.4小结聚合索引中的介绍!

-- 3. 查询语句中使用OR关键字:
-- 查询条件中有OR关键字时,如果OR前后的两个条件列都具有索引,则查询中索引将被使用,而如果OR前后有一个或2个列不具有索引,那么查询中索引将不被使用到!

  1. 什么是约束以及分类

约束:

作用:是为了保证数据的完整性而实现的摘自一套机制,即(约束是针对表中数据记录的)

MySQL中的约束:

  • 非空约束:NOT NULL 保证某列数据不能存储NULL 值;
  • 唯一约束:UNIQUE(字段名) 保证所约束的字段,数据必须是唯一的,允许数据是空值(Null),但只允许有一个空值(Null);
  • 主键约束:PRIMARY KEY(字段名) 主键约束= 非空约束 + 唯一约束 保证某列数据不能为空且唯一;
  • 外键约束:FOREIGN KEY(字段名) 保证一个表中某个字段的数据匹配另一个表中的某个字段,可以建立表与表直接的联系;
  • 自增约束:AUTO_INCREMENT 保证表中新插入数据时,某个字段数据可以依次递增;
  • 默认约束:DEFALUT 保证表中新插入数据时,如果某个字段未被赋值,则会有默认初始化值;
  • 检查性约束:CHECK 保证列中的数据必须符合指定的条件;

MySQL索引和约束的区别

  • 索引的作用:索引用于快速定位特定数据,提高查询效率的。
  • 约束的作用:约束是为了保证数据的完整性,即约束是针对表中数据记录的。
  • 总结:约束是为了保证表数据的完整性,索引是为了提高查询效率,两者作用不一样!种类也不太一样!

你可能感兴趣的:(mysql,java,数据库)