【MySQL】
事务
MySQL事务特性
MySQL 的事务特性由 ACID 原则定义,它确保了数据库操作的可靠性、稳定性和一致性。事务是一个逻辑上的操作单元,可以包含多个数据库操作,且这些操作要么完全执行(提交),要么完全不执行(回滚)。
ACID 原则
ACID 是事务的四大特性,分别是:
-
原子性(Atomicity):
-
事务中的操作要么全部成功执行,要么全部不执行。如果事务中的某个操作失败,事务会被回滚,数据库状态恢复到事务开始之前的状态。
-
示例:如果事务包含两个操作,第一操作成功,第二操作失败,那么整个事务会被回滚。
-
-
一致性(Consistency):
-
在事务开始之前和结束之后,数据库都应该处于一致的状态。事务的执行不会破坏数据库的完整性约束(如外键约束、检查约束等)。
-
示例:如果数据库执行一个插入操作,涉及到的表的约束(如唯一性、外键等)不会被违反。
-
-
隔离性(Isolation):
-
事务的执行不应受到其他事务的干扰,事务之间是隔离的。一个事务的中间状态对其他事务不可见。
-
示例:事务 A 正在更新某条记录,而事务 B 不能看到 A 的中间状态,即使 A 尚未提交。
-
-
持久性(Durability):
-
一旦事务提交,其对数据库的改变是永久性的,即使系统崩溃,也不会丢失。
-
示例:当事务提交之后,数据修改会被写入磁盘,不会因为系统崩溃而丢失。
-
MySQL 事务的实现
在 MySQL 中,事务通常与数据库的 存储引擎 密切相关。以 MySQL 常用的 InnoDB 存储引擎为例,MySQL 支持 ACID 事务特性。
1. 开启事务
在 MySQL 中,可以通过 SQL 语句 START TRANSACTION
或 BEGIN
来显式地开始一个事务。
START TRANSACTION;
-- 或者
BEGIN;
2. 提交事务
当事务中的所有操作都执行成功后,使用 COMMIT
语句提交事务,确保数据库的修改被永久保存。
COMMIT;
3. 回滚事务
如果事务中的某个操作失败,或者遇到异常情况,可以使用 ROLLBACK
来回滚事务,撤销事务中的所有操作,数据库恢复到事务开始前的状态。
ROLLBACK;
4. 自动提交模式
MySQL 默认是开启 自动提交模式(autocommit),即每执行一条 SQL 语句时,系统会自动提交操作。如果想要关闭自动提交,可以执行:
SET autocommit = 0;
关闭自动提交后,必须手动使用 COMMIT
或 ROLLBACK
来控制事务提交或回滚。
MySQL 的事务隔离级别
事务的隔离性(Isolation)是指事务在执行过程中,如何与其他事务并发执行时进行隔离,防止出现问题。MySQL 支持以下四种事务隔离级别(从低到高):
-
读未提交(Read Uncommitted):
-
事务可以读取其他事务未提交的数据(脏读)。
-
存在的问题:可能会读取到其他事务尚未提交的部分数据,导致读取脏数据。
-
-
读已提交(Read Committed):
-
事务只能读取其他事务已提交的数据。
-
存在的问题:可重复读问题,即一个事务中两次查询可能得到不同的结果,因其他事务已经提交了更改。
-
-
可重复读(Repeatable Read):
-
事务在开始后,每次查询返回的结果是固定的,即使其他事务修改了数据。
-
是 MySQL 默认的隔离级别,解决了脏读和不可重复读的问题,但仍然可能发生 幻读(phantom read)。
-
幻读:一个事务读取到的结果集,在同一个事务内再次读取时,其他事务插入的新数据可能会出现在结果集中。
-
-
串行化(Serializable):
-
最严格的隔离级别,事务之间会完全串行化执行,事务会按顺序一个接一个地执行。
-
该级别避免了脏读、不可重复读和幻读,但会大大降低并发性,性能较差。
-
可以通过以下 SQL 命令设置事务的隔离级别:
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
MySQL 事务的锁机制
MySQL 使用锁机制来确保事务的隔离性,不同的隔离级别会使用不同类型的锁。主要的锁有:
-
行级锁:InnoDB 支持行级锁,它能够保证同一行数据在并发情况下的隔离性。
-
表级锁:表级锁对整张表进行锁定,较少使用行级锁,通常发生在较低的事务隔离级别下。
-
意向锁:InnoDB 使用意向锁来指示事务是否希望对某些行加锁,从而避免死锁。
行级锁:
-
行级锁是 MySQL 中最细粒度的锁,它可以允许其他事务并行地访问不同的行。
-
行级锁会在某些情况下(如更新数据)自动获取。
表级锁:
-
当某事务需要锁住整张表时,系统会使用表级锁,通常会影响整个表的性能。
事务中的常见问题
-
脏读:一个事务读取到另一个事务未提交的数据。
-
解决:通过
Read Committed
或更高的隔离级别。
-
-
不可重复读:同一个事务中,读取相同的数据两次,结果不同。
-
解决:通过
Repeatable Read
隔离级别。
-
-
幻读:在同一事务中两次查询时,其他事务插入了新的记录,导致结果集发生变化。
-
解决:通过
Serializable
隔离级别。
-
总结
MySQL 事务的特性主要是通过 ACID 原则来保证数据的一致性、可靠性和稳定性。理解这些特性对于编写可靠的数据库应用程序至关重要,特别是在高并发和分布式系统中。事务的隔离级别和锁机制帮助管理并发执行中的数据一致性问题,而不同的隔离级别适用于不同的业务场景。
详细解释一下InnoDB 存储引擎。MySQL还有其他的存储引擎吗?
InnoDB 存储引擎详解
InnoDB 是 MySQL 的默认存储引擎,也是最常用的存储引擎之一。它以其 事务支持、行级锁、外键约束等特性而著名,适用于大多数需要高并发、数据一致性的应用场景。
1. 事务支持(ACID)
InnoDB 完全支持 ACID 事务特性,确保数据库操作的可靠性。具体来说:
-
原子性(Atomicity):InnoDB 支持原子性操作,即事务中的所有操作要么全部成功,要么全部失败。
-
一致性(Consistency):事务在完成后,数据库从一个一致的状态转变为另一个一致的状态,确保数据库约束不被破坏。
-
隔离性(Isolation):InnoDB 支持多种事务隔离级别(包括 读未提交、读已提交、可重复读、串行化),确保事务之间的操作互不干扰。
-
持久性(Durability):一旦事务提交,所有更改都会永久保存,即使发生系统崩溃也不会丢失。
2. 行级锁(Row-level Locking)
InnoDB 使用 行级锁 来控制并发操作,相比于 表级锁,行级锁能够提高并发性能。行级锁允许多个事务同时操作不同的行数据,极大地减少了锁竞争和阻塞。
-
锁粒度:行级锁只会锁定某一行,而不会影响到整个表的其他行,减少了锁冲突,提高了系统性能。
-
锁类型:
-
共享锁(S):允许其他事务读取数据,但不允许修改数据。
-
排他锁(X):允许其他事务修改数据,但不允许其他事务读取或修改该数据。
-
3. 外键支持
InnoDB 支持 外键约束,允许定义表与表之间的引用完整性。这对于防止数据不一致非常重要。外键约束的实现包括:
-
级联操作:如 级联更新(CASCADE) 和 级联删除(CASCADE),确保数据之间的关联性。
-
限制操作:如 SET NULL 或 RESTRICT,控制外键的行为。
4. 存储方式:聚簇索引(Clustered Index)
InnoDB 使用 聚簇索引(Clustered Index)来存储表数据。聚簇索引的特点是 数据存储与主键索引 是一起的,即表中的数据行按照主键顺序存储,这使得 主键索引 访问非常高效。
-
数据表的行数据 是 按主键索引排序存储 的,因此聚簇索引不仅是索引,还决定了数据的物理存储顺序。
-
每个表只能有一个聚簇索引,通常是 主键 索引。
-
对于没有主键的表,InnoDB 会选择 第一个 UNIQUE 索引 作为聚簇索引。
5. 双写缓冲(Doublewrite Buffer)
InnoDB 使用 双写缓冲机制来增强数据的持久性和一致性。每次数据修改时,InnoDB 会先将数据写入 双写缓冲区,然后再将数据写入实际的磁盘文件。这可以避免磁盘故障时数据丢失,确保数据的安全性。
6. 数据恢复机制:重做日志和回滚日志
InnoDB 采用了日志文件(redo log)和 回滚日志(undo log) 来保证数据的恢复性和一致性。
-
重做日志(redo log):记录事务对数据的修改,确保即使发生系统崩溃,数据也能通过重做日志恢复。
-
回滚日志(undo log):用于事务回滚时,撤销对数据的修改。
这些日志帮助 InnoDB 实现 崩溃恢复,确保在数据库崩溃后能够恢复到事务提交之前的状态。
MySQL 其他存储引擎
除了 InnoDB,MySQL 还支持其他多种存储引擎,每种存储引擎有不同的特点,适用于不同的应用场景。下面是常见的几个 MySQL 存储引擎:
1. MyISAM
MyISAM 是 MySQL 的传统存储引擎,主要用于只读操作比较多的应用场景。与 InnoDB 相比,MyISAM 有一些特点:
-
不支持事务:MyISAM 不支持事务处理(不支持 ACID)。
-
表级锁:MyISAM 使用 表级锁,每次只能有一个线程访问某个表,限制了并发性能。
-
高效的查询性能:在只读查询较多的情况下,MyISAM 性能表现较好,特别是对于复杂查询。
-
不支持外键约束:MyISAM 不支持外键和引用完整性。
2. MEMORY
MEMORY 存储引擎使用内存来存储所有表数据,数据的读取和写入速度非常快。其特点包括:
-
数据存储在内存中:表数据完全保存在 RAM 中,数据访问速度极快。
-
临时性:数据是暂时存储的,MySQL 服务器重启后,所有数据都会丢失。
-
表级锁:MEMORY 存储引擎使用表级锁,不支持行级锁。
-
适合临时表:适用于快速的、临时的数据存储,如会话管理、缓存等。
3. CSV
CSV 存储引擎用于将数据存储为 CSV(逗号分隔值)文件。它的特点有:
-
文件格式:数据以 CSV 格式存储,便于与其他系统进行交换。
-
没有索引:不支持索引,因此查询性能较差,适用于轻量级的数据存储。
4. NDB (Cluster)
NDB 存储引擎是 MySQL 集群(MySQL Cluster)的引擎。它提供了高可用性、高容错性的分布式数据库解决方案。
-
分布式存储:数据被分布在多个节点上,支持 水平扩展。
-
高可用性和容错性:提供数据的冗余存储,可以在节点失败时自动恢复。
-
适用于高并发和高可用的分布式系统。
5. TokuDB
TokuDB 存储引擎采用了 Fractal Tree 索引,适用于大数据量、高写入负载的场景。它的优点包括:
-
高效的数据压缩:TokuDB 对数据进行高效压缩,减少了存储空间需求。
-
高效的写入性能:在写入性能上比传统的 InnoDB 更强,特别是在处理大规模数据时。
-
适合大数据量应用:适用于大规模、频繁写入和查询的场景。
6. Archive
Archive 存储引擎适用于存储大量历史数据,其特点包括:
-
只支持 INSERT 和 SELECT 操作,不支持更新或删除数据。
-
高压缩比:数据存储时被压缩,节省磁盘空间。
-
适合归档存储:适合存储历史记录、日志数据等。
总结
-
InnoDB 是 MySQL 的默认存储引擎,提供了事务支持、行级锁、外键约束等特性,适用于大多数应用。
-
MySQL 还支持其他存储引擎,如 MyISAM(不支持事务,适用于只读操作)、MEMORY(内存存储,适用于高速缓存和临时数据)、CSV(CSV 文件格式存储)等,每种存储引擎都有其适用的场景。
了解不同存储引擎的特性,可以帮助你根据实际需求选择最合适的存储引擎,提升数据库的性能和稳定性。
外键约束是什么?
外键约束是关系型数据库中用于保证数据一致性和完整性的机制。它是指在两个表之间建立的一个约束,确保一个表中的某个字段(外键)对应另一个表中的主键或唯一键。外键约束用于 维护表与表之间的关系,并确保数据的一致性和完整性。
具体来说,外键约束确保以下几点:
-
参照完整性:外键值必须是另一张表中的有效值,即外键所引用的主键(或唯一键)必须存在。
-
避免无效数据:防止插入不符合关系的数据,避免引用不存在的记录。
-
数据级联操作:在删除或更新被引用的数据时,可以自动触发一些操作(如级联删除、级联更新等)。
外键约束的作用
-
数据一致性:外键约束确保表与表之间的数据关系是有效的。例如,订单表中的
customer_id
外键必须指向客户表中的一个有效的id
,从而确保每个订单都对应一个有效的客户。 -
数据完整性:通过外键约束,数据库能够防止不合法的操作,如插入一个在引用表中不存在的外键值、删除一个在其他表中被引用的记录等。
-
自动维护引用关系:通过级联操作,外键可以自动管理表之间的引用。例如,当删除父表中的记录时,可以自动删除所有引用该记录的子表数据,确保没有孤立的数据。
外键约束的基本语法
在创建或修改表时,可以使用 FOREIGN KEY
关键字来定义外键约束。
1. 创建表时定义外键
假设我们有两个表:orders
表和 customers
表,其中 orders
表中的 customer_id
字段是 customers
表的外键,引用了 customers
表中的主键 id
。
CREATE TABLE customers (id INT PRIMARY KEY,name VARCHAR(100) NOT NULL
);CREATE TABLE orders (order_id INT PRIMARY KEY,order_date DATE,customer_id INT,FOREIGN KEY (customer_id) REFERENCES customers(id) -- 外键约束
);
在上面的例子中:
-
orders
表中的customer_id
字段是外键,它引用了customers
表的id
字段。 -
当我们向
orders
表插入数据时,customer_id
字段的值必须是customers
表中存在的id
。
2. 修改表时添加外键
如果表已经存在,可以使用 ALTER TABLE
语句添加外键约束。
ALTER TABLE orders
ADD CONSTRAINT fk_customer_id FOREIGN KEY (customer_id) REFERENCES customers(id);
外键的操作规则
外键约束支持一些常见的操作规则,用于管理父表和子表之间的数据一致性,尤其是当父表的数据发生更改(删除或更新)时,子表的数据应该如何变化。
这些操作规则包括:
-
CASCADE(级联):
-
级联删除:当父表中的记录被删除时,子表中所有引用该记录的外键值也会被删除。
-
级联更新:当父表中的记录的主键值被更新时,子表中所有引用该主键的外键值也会相应更新。
示例:
CREATE TABLE orders (order_id INT PRIMARY KEY,customer_id INT,FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE CASCADE ON UPDATE CASCADE );
-
-
SET NULL:
-
当父表中的记录被删除或更新时,子表中引用该记录的外键值会被设置为
NULL
。
示例:
CREATE TABLE orders (order_id INT PRIMARY KEY,customer_id INT,FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE SET NULL ON UPDATE SET NULL );
-
-
RESTRICT:
-
删除或更新操作被拒绝:如果父表中有引用该记录的子表记录,则不允许删除或更新父表中的记录。
示例:
CREATE TABLE orders (order_id INT PRIMARY KEY,customer_id INT,FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE RESTRICT ON UPDATE RESTRICT );
-
-
NO ACTION:
-
与
RESTRICT
类似,表示没有任何操作。如果父表记录被删除或更新,子表会受到限制,不允许进行操作。
示例:
CREATE TABLE orders (order_id INT PRIMARY KEY,customer_id INT,FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE NO ACTION ON UPDATE NO ACTION );
-
-
SET DEFAULT:
-
当父表中的记录被删除或更新时,子表中的外键值会被设置为默认值(需要定义字段的默认值)。
示例:
CREATE TABLE orders (order_id INT PRIMARY KEY,customer_id INT DEFAULT 0,FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE SET DEFAULT ON UPDATE SET DEFAULT );
-
外键约束的注意事项
-
外键的目标必须是主键或唯一键: 外键必须引用另一个表中的主键或者唯一键(
UNIQUE
键),以确保参照完整性。 -
插入数据时的外键约束: 在插入数据时,外键字段的值必须是引用表中已经存在的主键值。否则,插入会失败。
例如,在
orders
表中插入一个没有对应customer_id
的记录时,数据库会拒绝插入。 -
外键约束的性能开销: 虽然外键约束可以保证数据一致性和完整性,但它也会带来一定的性能开销,特别是在插入、更新或删除时需要检查外键约束的情况下。因此,在一些对性能要求极高的应用中,可以考虑是否使用外键约束。
-
删除父表记录时的外键约束: 在删除父表记录时,如果该记录被子表引用,删除操作会受到外键约束的影响(根据外键的规则,如
CASCADE
、SET NULL
或RESTRICT
)。 -
外键的级联操作: 外键约束支持级联操作,可以确保父表记录的删除或更新操作被自动传播到子表。这对于处理表之间的引用关系非常有用。
总结
外键约束是关系型数据库中用来保证数据一致性和完整性的关键机制。通过外键,数据库能够确保一个表中的数据是有效的、可引用的,并且在父表记录更改时,能够通过级联操作自动维护数据的完整性。
外键约束不仅有助于提高数据的可靠性和一致性,还能减少人为错误。理解并正确使用外键约束,有助于设计更加健壮的数据模型。
MySQL有哪些索引
MySQL 支持多种类型的索引,每种索引类型都有不同的特性和适用场景。索引是数据库中提高查询效率的核心机制,通过创建索引,数据库能够更快地查找和访问数据。
以下是 MySQL 中常见的索引类型及其特点:
1. 普通索引(Index)
-
普通索引 是最基本的索引类型,它没有任何限制。通过普通索引,数据库可以加速查询操作。
-
使用场景:适用于需要加速查询的字段,但并不要求字段值是唯一的。
创建普通索引:
CREATE INDEX idx_column_name ON table_name (column_name);
2. 唯一索引(Unique Index)
-
唯一索引 与普通索引类似,但它要求索引列的值必须唯一。也就是说,插入数据时,数据库会自动检查该字段的值是否已存在于索引中。
-
使用场景:适用于字段值唯一的场景,如用户名、电子邮件等。
-
优点:能够保证数据的唯一性。
创建唯一索引:
CREATE UNIQUE INDEX idx_column_name ON table_name (column_name);
3. 主键索引(Primary Key)
-
主键索引 是一种特殊的唯一索引,它不仅要求字段值唯一,还要求该字段值不能为空(
NOT NULL
)。一个表只能有一个主键。 -
使用场景:通常用于标识表中的唯一记录,如用户ID、订单ID等。
-
优点:主键索引本身就是唯一的,并且是数据库表的标识符。
-
注意:主键索引在创建时会隐式创建一个唯一索引。
创建主键索引:
CREATE TABLE table_name (id INT NOT NULL PRIMARY KEY,name VARCHAR(50)
);
4. 全文索引(Full-text Index)
-
全文索引 是一种特殊的索引类型,用于处理文本数据,特别是在对大文本进行查询时,能够显著提高效率。
-
使用场景:适用于对字符串字段(如文章内容、评论等)进行全文检索的场景。
-
注意:MySQL 的全文索引只支持 MyISAM 和 InnoDB 存储引擎,且对字符集有要求(如支持
utf8mb4
字符集)。
创建全文索引:
CREATE FULLTEXT INDEX idx_fulltext ON table_name (column_name);
查询时使用全文索引:
SELECT * FROM table_name WHERE MATCH(column_name) AGAINST('search_term');
5. 组合索引(Composite Index)
-
组合索引 是指在多个列上创建的索引。它通过将多个列的值组合在一起,来加速基于多个列的查询。
-
使用场景:适用于多列查询中包含多个字段作为查询条件的情况。组合索引不仅加速查询,还能减少磁盘空间的使用。
-
注意:组合索引的顺序非常重要,查询时字段的顺序要与索引的顺序一致才能充分发挥组合索引的作用。
创建组合索引:
CREATE INDEX idx_combined ON table_name (column1, column2);
6. 空间索引(Spatial Index)
-
空间索引 用于空间数据类型(如
GEOMETRY
类型)的查询,它加速空间数据的存储和查询。 -
使用场景:常用于地理信息系统(GIS)或其他需要处理空间数据的应用。
创建空间索引:
CREATE SPATIAL INDEX idx_spatial ON table_name (spatial_column);
7. 前缀索引(Prefix Index)
-
前缀索引 允许你在字符串列的前几位创建索引,而不是整个字符串。这对于长文本字段非常有效,可以节省存储空间。
-
使用场景:适用于
VARCHAR
或TEXT
类型字段,尤其是字段值较长时,可以创建前缀索引来优化查询性能。 -
注意:前缀索引只能在字符串类型列上创建。
创建前缀索引:
CREATE INDEX idx_prefix ON table_name (column_name(10)); -- 只对前10个字符建立索引
8. 自增索引(Auto_increment)
-
自增索引 不是一种独立的索引类型,而是针对 主键 字段的特性。自增字段通常用作表的主键,自动为每条记录分配唯一的整数值。
-
使用场景:适用于需要生成唯一标识符的场景,如 ID 字段。
创建自增字段:
CREATE TABLE table_name (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,name VARCHAR(50)
);
9. 聚簇索引(Clustered Index)
-
聚簇索引 是一种特殊类型的索引,InnoDB 存储引擎默认使用聚簇索引。与其他索引不同,聚簇索引将数据存储在索引结构中,即表的记录本身是按索引顺序存储的。
-
使用场景:适用于经常进行范围查询或排序的场景。
注意:InnoDB 存储引擎自动使用 主键索引 作为聚簇索引,如果没有主键,它会选择 第一个唯一索引 作为聚簇索引。
10. 索引的存储结构:B+树索引
-
B+树索引 是 MySQL 中大多数索引(如 普通索引、唯一索引、主键索引 等)使用的默认数据结构。它是 B树的一种变体,通过链式结构将所有叶子节点链接在一起。
-
优点:支持高效的范围查询和排序操作,查询性能非常优秀。
总结
MySQL 提供了多种索引类型,每种类型都有特定的应用场景和特点,以下是常见的索引类型总结:
-
普通索引:没有任何约束,适用于普通查询。
-
唯一索引:要求索引列的值唯一,适用于唯一字段。
-
主键索引:是唯一索引的一种,且不能为 NULL。
-
全文索引:适用于文本字段的全文搜索。
-
组合索引:在多个列上创建索引,适用于多列查询。
-
空间索引:用于空间数据类型(如
GEOMETRY
)。 -
前缀索引:用于长文本字段,索引字段的前缀部分。
-
自增索引:常用于主键字段,自动生成唯一值。
-
聚簇索引:数据按主键或唯一索引顺序存储,InnoDB 默认使用。
聚簇索引以及它与非聚簇索引的区别
聚簇索引(Clustered Index)
聚簇索引 是一种特殊类型的索引,它决定了数据存储的物理顺序。在 MySQL 的 InnoDB 存储引擎中,聚簇索引是数据存储的核心结构。当表中的数据按照某个列进行索引时,这个索引就是聚簇索引。
聚簇索引的特点
-
数据和索引的存储方式:
-
聚簇索引将表的 数据行本身 存储在索引的叶子节点中。也就是说,数据和索引是一起存储的。
-
表的数据按 主键索引(如果没有主键,使用其他唯一索引)排序,并存储在聚簇索引的叶子节点中。
-
-
一个表只能有一个聚簇索引:
-
因为聚簇索引决定了数据的物理存储顺序,每个表只能有一个聚簇索引。通常情况下,聚簇索引就是主键索引。
-
-
主键索引默认是聚簇索引:
-
如果没有显式指定聚簇索引,InnoDB 会自动将表的主键作为聚簇索引。
-
如果表没有定义主键,InnoDB 会选一个 唯一索引 作为聚簇索引。
-
如果没有主键,也没有唯一索引,那么 InnoDB 会隐式地创建一个 6字节的隐式主键 来存储。
-
-
物理顺序与索引顺序一致:
-
聚簇索引中的叶子节点存储的是表的 实际数据,因此数据的物理存储顺序与索引顺序是一样的。也就是说,主键索引的顺序决定了数据的物理顺序。
-
-
聚簇索引的查询效率:
-
查询聚簇索引时,因为数据本身就是按照索引顺序存储的,所以在查询时可以通过索引直接访问数据,减少了磁盘 I/O 操作,查询效率较高。
-
聚簇索引的工作原理
假设我们有一个表 users
,其结构如下:
CREATE TABLE users (id INT PRIMARY KEY, -- 主键索引name VARCHAR(50),age INT
);
-
表的 主键 列
id
是聚簇索引,表的 数据行 将按照id
列的顺序存储在磁盘中。 -
通过主键索引查找数据时,可以直接定位到数据的位置,因此聚簇索引是最有效的索引之一。
聚簇索引的优势与劣势
-
优势:
-
查询性能较好:特别是对主键或唯一索引进行范围查询时,因数据按索引顺序存储,能够快速定位数据。
-
减少了磁盘 I/O:索引与数据存储在一起,可以减少磁盘的读取次数。
-
-
劣势:
-
数据更新时会更耗时:因为表的实际数据存储顺序是根据索引排序的,如果插入、更新数据,会涉及到数据页的重新排列。
-
只能有一个聚簇索引:一个表只能有一个聚簇索引,因此对于非主键列的查询可能会比较慢。
-
非聚簇索引(Non-clustered Index)
非聚簇索引 是指索引本身和数据的存储是分开的。在非聚簇索引中,索引存储了列的值和指向表中数据的指针(即 行地址),而数据行是按照其他方式(如主键或其他唯一索引)存储的。
非聚簇索引的特点
-
索引与数据分开存储:
-
非聚簇索引不影响表数据的物理存储顺序,它仅仅存储列值和指向实际数据行的指针。
-
索引本身是一个独立的结构,通常会有一棵 B+树 来组织索引。
-
-
多个非聚簇索引:
-
一个表可以有多个非聚簇索引。这意味着你可以在表中为不同的列创建多个索引,以加速不同类型的查询。
-
-
存储方式:
-
在非聚簇索引中,叶子节点存储的是 索引值 和 指向数据行的指针,而数据行不按照任何索引的顺序存储。
-
索引的叶子节点是通过指针与数据行关联的,查询时需要通过索引定位到数据行。
-
非聚簇索引的工作原理
假设我们创建了一个 name
列的非聚簇索引:
CREATE INDEX idx_name ON users (name);
-
非聚簇索引
idx_name
会创建一棵 B+ 树,树的叶子节点存储的是name
字段的值和指向users
表对应数据行的指针。 -
当查询时,MySQL 会先通过非聚簇索引查找
name
,然后通过索引中的指针去访问实际的表数据。
非聚簇索引的优势与劣势
-
优势:
-
可以创建多个非聚簇索引:可以为不同的列创建多个索引,适用于不同类型的查询。
-
查询灵活:可以为常用的查询列创建索引,提高查询效率。
-
-
劣势:
-
查询效率低于聚簇索引:因为查询时需要先通过索引查找,再通过指针访问数据行,比聚簇索引多了一个步骤,性能上较为低效。
-
存储开销大:每增加一个非聚簇索引,都需要占用额外的存储空间。
-
更新代价高:对数据的更新会涉及到非聚簇索引的维护,导致更新操作较为耗时。
-
聚簇索引 vs 非聚簇索引
特性 | 聚簇索引(Clustered Index) | 非聚簇索引(Non-clustered Index) |
---|---|---|
数据存储顺序 | 数据按索引顺序存储在磁盘中,数据和索引存储在一起。 | 数据和索引是分开的,数据存储顺序与索引顺序无关。 |
表中索引数量 | 一个表只能有一个聚簇索引。 | 一个表可以有多个非聚簇索引。 |
存储结构 | 存储的是数据本身,叶子节点直接存储数据行。 | 存储的是索引值和指向数据行的指针,叶子节点存储指针。 |
查询性能 | 对于范围查询和主键查询效率高。 | 查询时需要先查索引,再通过指针访问数据,性能相对较低。 |
插入与更新性能 | 插入和更新时可能导致数据重新排列,因此性能较低。 | 插入和更新时不会影响数据行的顺序,但需要维护索引。 |
存储空间 | 只需要存储一个聚簇索引,空间较节省。 | 每个非聚簇索引都会占用额外的存储空间。 |
总结
-
聚簇索引:将数据行存储在索引的叶子节点中,索引决定了数据的物理存储顺序。一个表只能有一个聚簇索引,通常是主键索引。对于范围查询或基于主键的查询性能非常好。
-
非聚簇索引:索引存储了列值和数据行的指针,数据和索引分开存储。一个表可以有多个非聚簇索引,适用于加速各种不同的查询。
在数据库设计中,我们通常将 主键索引 作为聚簇索引,其他索引则使用非聚簇索引来加速查询。