1. 什么是索引?
索引是数据库表中一种用于提高数据查询效率的数据结构。通过索引,数据库可以更快速地查找特定到数据,类似书籍的目录帮助读者快速定位内容。
在MySQL中,索引相当于表的一种数据结构(如B树、存储表等),用于存储特定字段的分区数据。创建索引后,数据库在查询数据时会通过索引快速定位数据,而不是扫描整个表,从而大大提升查询效率。
2. 为什么使用索引?
索引的主要目的是提高数据库的查询速度。对于大规模的数据表来说,没有索引的查询效率会非常低。特别是数据表特定行数据分布时,查询某个条件的数据可能需要逐行扫描所有数据(即全表扫描),运行且资源占用大。有了索引,查询可以直接定位到符合条件的数据,从而显着减少数据库的查询时间。
索引特性:
- 提升查询速度,减少查询时间。
- 提升排序速度,避免使用临时表进行排序。
索引的优缺点:
- 索引会占用磁盘空间,尤其是复合会增加数据表的存储。
- 间歇地增删改操作会导致索引的维护成本增加,拖慢增删改的速度。
3. MySQL中索引的种类
MySQL中支持多种索引类型,常用的有以下几种:
- 主键索引(Primary Key Index)
- 唯一索引 (Unique Index)
- 普通索引(Index)
- 全文索引(全文索引)
- 聚集索引
- 非聚集索引
- 索引覆盖
4.索引的创建和使用示例
下面,我们来详细介绍索引的用法和MySQL代码示例。
1. 主键索引
主键索引是数据库中最常见的一种索引类型,用于唯一表中的每一行记录。在MySQL中,主键索引既是一种约束,也是一种特殊的索引。主键(Primary Key)是一种列或列组合,其值是唯一且非空的。
1.主键索引
- 唯一性:主键索引保证列中的每个值都是唯一的,不允许重复。
- 非空性 :主键列不能包含
NULL
值。 - 自动创建索引:定义主键后,MySQL会自动为该列创建一个唯一的索引,因此,数据检索时会使用该索引来加速查询。
- 一张表只能有一个主键:在一个表中,只能有一个主键索引,但主键索引可以由多个列组成,即"复合主键"。
2. 主键索引的作用
主键索引的主要作用是为表中的每一行提供唯一的标识,以便快速快速检索和管理数据。由于主键索引唯一且非空,它适合使用一行记录的唯一标识,在进行增删改操作时尤其如此例如,通常在UPDATE
和DELETE
语句操作中使用主键作为条件来定位要的记录。
3. 如何创建主键索引
MySQL中可以通过以下方式创建主键索引:
3.1 在创建表时定义主键
在表的定义阶段可以指定主键。常用的写法是在CREATE TABLE
语句中直接设置主键约束。
CREATE TABLE employees (
employee_id INT NOT NULL,
name VARCHAR(50),
age INT,
PRIMARY KEY (employee_id) -- employee_id字段作为主键索引
);
3.2 创建复合主键
在有多个列需要组合成唯一标识时,可以定义复合主键。复合主键使用两个或多个列来保证唯一性。
CREATE TABLE orders (
order_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT,
PRIMARY KEY (order_id, product_id) -- order_id和product_id组合作为复合主键
);
3.3 在已有表上添加主键索引
可以在创建表之后使用ALTER TABLE
语句为现有表添加主键索引。
ALTER TABLE employees ADD PRIMARY KEY (employee_id);
4. 主键索引的使用示例
4.1 查询数据
使用主键索引可以显着提升查询效率。例如,我们可以直接使用主键索引employee_id
来快速查询特定记录:
SELECT * FROM employees WHERE employee_id = 1001;
由于employee_id
是主键,MySQL会使用主键索引来加速查询。
4.2 更新数据
在更新数据时,使用主键可以快速定位目标记录并进行修改:
UPDATE employees SET age = 30 WHERE employee_id = 1001;
这条语句使用主键employee_id
定位记录,MySQL会根据主键索引快速找到对应记录并更新age
列的值。
4.3 删除数据
主键索引同样适用于删除操作,因为可以快速确定要删除的行:
DELETE FROM employees WHERE employee_id = 1001;
由于主键employee_id
拥有唯一索引,MySQL可以快速找到对应行并执行删除操作。
5. 主键索引的存储结构(B+树)
MySQL InnoDB存储引擎使用B+树结构来存储主键索引。以下是B+树在主键索引中的作用:
- 快速插入:B+树是一种平衡树结构,能够让数据插入和查找保持高效。
- 自动排序:主键列中的数据会按照B+树结构自动排序,因此主键索引可以加速数据范围查询和排序查询。
- 聚簇索引:在InnoDB存储引擎中,主键索引为聚簇索引(Clustered Index),表中的数据按主键顺序存储。其他索引通过主键索引来定位数据。
6. 主键索引的优缺点
优点
- 查询效率高:主键索引是唯一且非空的,适合快速定位记录,特别是在查询、更新、删除时。
- 数据完整性:主键约束可确保每行数据的唯一性和非空性,避免重复数据。
- 自动排序:主键索引的数据是自动排序的,适合按顺序查询。
- 适用于聚簇索引:InnoDB引擎中主键索引是聚簇索引,数据按主键存储,可高效支持范围查询。
缺点
- 限制只有一个:每个表只能定义一个主键,有灵活的。
- 插入性能影响:如果主键是随机值(如UUID),会影响B+树的平衡,导致插入性能下降。通常自增的整数主键比较合适。
- 修改不便:主键一旦定义,不适合修改,因为会影响B+树结构。
- 占用空间:主键索引需要存储B+树结构,占用额外的磁盘空间。
7. 主键索引使用注意事项
- 选择合适的字段 :主键索引通常使用频率对应且唯一的字段,例如
id
。 - 避免使用随机值主键:避免使用UUID或随机数作为主键,因为这会导致B+树的非顺序插入,影响性能。
- 尽量不要更新主键字段:主键更新会导致B+树重新组织,影响性能。
- 自增主键的优点:自增的整数主键性能高且节省存储空间,适合大多数应用场景。
8. 主键索引的性能分析
可以使用EXPLAIN
关键字查看主键索引的使用情况。例如:
EXPLAIN SELECT * FROM employees WHERE employee_id = 1001;
EXPLAIN
的输出会显示是否使用了主键索引来加速查询。如果速度查询条件是主键字段,MySQL会自动选择主键索引来优化查询。
2.普通索引
普通索引 (通常称为"索引")是MySQL中最基础的一种索引类型,主要用于加速查询性能,但没有任何唯一性限制。因此,普通索引允许重复值和NULL
值,适合那些查询严密,但需要唯一性保证的字段上。
1.普通索引
- 无唯一性 :普通索引不限制字段的值是否唯一,可以包含重复值和
NULL
值。 - 提升查询速度:普通索引加速了数据搜索,但不像主键或唯一索引那样有约束功能。
- 支持多个普通索引:一个表可以有多个普通索引。
- 多种存储引擎支持 :普通索引支持的存储引擎坐标,如
InnoDB
、MyISAM
等。
2. 普通指标的作用
普通索引的作用是提升查询效率,特别是对数据表的某些字段进行筛选或排序时,普通索引可以显着减少数据扫描量,提升查询速度。例如,对包含大量数据的列进行条件过滤、排序等操作时,普通索引可以避免全表扫描,加速查询。
3.普通索引的创建方式
在MySQL中,可以通过以下几种方式来创建普通索引:
3.1 在创建表时定义普通索引
可以在CREATE TABLE
语句中直接指定要创建的普通索引:
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(50),
age INT,
department_id INT,
INDEX idx_department_id (department_id) -- department_id字段为普通索引
);
3.2 在已存在的表上添加普通索引
如果表已经存在,可以使用ALTER TABLE
语句为特定字段添加普通索引:
ALTER TABLE employees ADD INDEX idx_age (age); -- age字段添加普通索引
3.3 使用CREATE INDEX
语句创建普通索引
除了在创建表时直接定义和使用ALTER TABLE
语句外,还可以使用CREATE INDEX
语句单独创建普通索引:
CREATE INDEX idx_name ON employees (name); -- name字段添加普通索引
4. 普通索引的使用示例
创建普通索引后,就可以使用该索引加速查询了。以下是普通索引在查询中的常见使用示例。
4.1 简单查询
假设我们在employees
表中的department_id
字段上创建了普通索引,现在可以通过该索引来加速查询:
SELECT * FROM employees WHERE department_id = 5;
MySQL会使用department_id
普通索引,避免全表扫描,快速定位符合条件的行。
4.2 排序查询
如果对某个字段进行排序查询时,字段上存在索引,那么MySQL会直接使用索引加速排序。假设在age
字段上创建了普通索引:
SELECT * FROM employees ORDER BY age ASC;
由于age
字段有索引,MySQL可以直接从索引中获取排序后的结果,避免了额外的排序计算。
4.3 范围查询
普通索引也适合范围查询。比如查询某个范围内的年龄记录:
SELECT * FROM employees WHERE age BETWEEN 25 AND 35;
MySQL会使用age
字段上的普通索引快速查找年龄在25到35之间的记录。
5. 普通索引的存储结构
在InnoDB
引擎中,普通索引采用B+树结构,称为非聚簇索引(Secondary Index)。其存储特点如下:
- B+树结构:普通索引以B+树结构存储,从而快速查找、范围查询。
- 指向主键 :在
InnoDB
中,普通索引的叶子节点存储的是主键值(而不是数据行本身)。因此,通过普通索引查找到数据后,MySQL还需要通过主键索引再次查找数据行(称为"回")表"操作)。 - 非聚簇索引:普通索引为非聚簇索引,数据和索引分开存储,因此每次查询时会多次回表开销。
6. 普通索引的优缺点
优点
- 提升查询性能:普通索引提升了数据筛选、排序和范围查询的速度,避免全表扫描。
- 支持多个普通索引:一张表上可以有多个普通索引,对不同的查询条件进行优化。
- 灵活 :普通索引允许重复值和
NULL
,适合那些不需要唯一性约束的字段。
缺点
- 增加存储空间:普通索引需要额外的存储空间,尤其是索引字段多时,会增加表的存储需求。
- 影响写操作性能:在插入、更新、删除时,普通索引需要额外维护,这会影响写操作的性能。
- 回表索引头部 :在
InnoDB
中,普通的叶子节点不直接存储行数据,查找后还需要回表查找主键,增加了一次访问成本。
7. 普通索引的使用和优化
MySQL中的普通索引可以显着提升查询性能,但补足索引会增加存储成本、写入成本和管理复杂性。以下是一些普通索引的优化建议:
7.1 为高频查询字段创建索引
应优先考虑那些在WHERE
条件、ORDER BY
、GROUP BY
、JOIN
等操作中高频使用的字段创建普通索引。通过减少不必要的全表扫描来提升性能。
7.2 避免在低索引字段上建立普通索引
索引是列中的不同值的数量和总行数的比例。低索引的字段(如性别、状态标志等)通常不适合创建索引,因为使用索引的效果不明显。例如**:**
ALTER TABLE employees ADD INDEX idx_gender (gender); -- 性别字段选择性低,通常不推荐添加索引
索引高的字段,使用索引可以显着减少扫描行数,效果更佳。
7.3 充分利用索引
覆盖索引 是指在查询时,所以需要的字段都包含在索引中,避免回表查询。例如,假设employees
表中的name
和age
字段是查询时用到的,可以在这两个字段上创建复合索引:
ALTER TABLE employees ADD INDEX idx_name_age (name, age);
当查询name
和age
字段时,可以直接从索引中获取数据,省去访问表的主键,从而减少回表开销:
SELECT name, age FROM employees WHERE name = 'Alice';
7.4 使用EXPLAIN查看索引使用情况
可以通过EXPLAIN
语句查看查询的执行计划,判断MySQL是否使用了索引:
EXPLAIN SELECT * FROM employees WHERE department_id = 5;
EXPLAIN
输出的key
字段显示MySQL使用的索引。通过EXPLAIN
可以诊断索引是否有效,以及是否需要优化。
8、普通索引使用注意事项
- 合理选择字段:普通索引适用于数据筛选的字段,但要避免在低索引字段上建立索引。
- 关注写入性能:在高吞吐量读取场景中,索引过多会显着降低插入、更新性能。
- 定期维护索引:对于高频更新的表,定期进行优化每个索引碎片,保证查询性能。
- 避免索引:避免在字段组合上创建重复索引,这样会占用额外的存储空间而影响写入性能。
3.唯一索引(Unique Index)
唯一索引(Unique Index)是MySQL中的一种用于保证列中数据唯一性的索引类型。通过唯一索引,可以保证一个表中的某个字段(或字段组合)不包含重复的值。唯一索引既是一个约束,也是一个指标,因此可以在提升查询效率的同时,维护数据的一致性和完整性。
1. 唯一索引
- 唯一性:唯一性指标要求列中的每个值都是唯一的,保证数据的完整性和一致性。
- 允许NULL值:允许唯一索引列包含NULL值,但在大多数数据库引擎中,每个NULL值被视为不同的,因此可以多个NULL。
- 唯一多个索引:一张表上可以定义多个唯一索引,但每个唯一索引必须对应的字段值组合唯一。
- 自动创建索引:定义唯一约束时,MySQL会自动创建一个唯一索引,因此数据搜索时会使用该索引来加速查询。
2. 唯一索引的作用
唯一索引的主要作用是保证数据的唯一性,同时加速查询。通常用于像用户名、邮箱、身份证号等需要唯一性的提升字段上。唯一索引也能查询效率,尤其是在查询涉及到唯一值或唯一组合的情况下,MySQL会利用唯一索引来快速定位记录。
3.唯一索引的创建方式
在MySQL中可以通过以下方式创建唯一索引:
3.1 在创建表时定义唯一索引
在创建表时,可以直接在CREATE TABLE
语句中为字段设置唯一索引:
CREATE TABLE users (
id INT PRIMARY KEY,
username VARCHAR(50),
email VARCHAR(100),
UNIQUE (username), -- 为username字段创建唯一索引
UNIQUE (email) -- 为email字段创建唯一索引
);
3.2 创建复合唯一索引
可以将多个字段组合组成唯一索引,保证字段组合的值在表中唯一的。通常为了保证某些字段组合在记录中唯一,例如商品ID和商店ID组合唯一的情况:
CREATE TABLE orders (
order_id INT,
store_id INT,
product_id INT,
UNIQUE (store_id, product_id) -- store_id和product_id组合作为唯一索引
);
3.3 在已有表上添加唯一索引
可以通过ALTER TABLE
语句为现有表添加唯一索引:
ALTER TABLE users ADD UNIQUE (email); -- 为email字段添加唯一索引
3.4 使用CREATE UNIQUE INDEX
语句创建唯一索引
还可以使用CREATE UNIQUE INDEX
语句创建唯一索引:
CREATE UNIQUE INDEX idx_unique_email ON users (email); -- 为email字段创建唯一索引
4.唯一索引的使用示例
定义唯一索引后,在插入或更新数据时,MySQL会自动验证字段值的唯一性。另外,唯一索引也用于查询优化。以下是一些唯一索引的使用场景和查询示例。
4.1 插入数据时的唯一性验证
假设username
字段是唯一索引,如果尝试插入重复的username
,则会引发错误:
INSERT INTO users (username, email) VALUES ('john_doe', 'john@example.com');
-- 如果再次插入相同的username值
INSERT INTO users (username, email) VALUES ('john_doe', 'john2@example.com');
-- 会导致错误:Duplicate entry 'john_doe' for key 'username'
4.2 更新数据时的唯一性验证
在更新数据时,如果唯一索引字段的目标值且记录重复,会引发错误。例如:
UPDATE users SET username = 'john_doe' WHERE id = 2;
-- 如果已存在一个用户记录的username是'john_doe',则会导致唯一索引冲突错误
4.3 使用唯一索引加速查询
假设在email
字段上有唯一索引,可以快速查询特定的记录:
SELECT * FROM users WHERE email = 'john@example.com';
MySQL会使用email
上的唯一索引,避免全表扫描,直接定位到符合条件的行。
4.4 复合唯一索引查询
假设在orders
表中,store_id
和product_id
字段上创建了复合唯一索引。查询时可以利用复合唯一索引加速组合查询:
SELECT * FROM orders WHERE store_id = 1 AND product_id = 1001;
由于store_id
和product_id
的组合是唯一索引,MySQL会直接使用索引,提升查询速度。
5. 唯一索引的存储结构
在InnoDB
引擎中,唯一索引采用B+树存储结构,其特点如下:
- B+树结构:唯一索引采用B+树结构存储,能够快速查找并保证唯一性。
- 叶子节点主键或数据:唯一叶子节点中的主键或数据地址,以便快速查找到对应数据。
- 约束和加速查询:唯一索引会在插入和更新时自动检查是否有重复数据,同时查询时也可以使用唯一索引加速。
6. 唯一索引的优缺点
优点
- 保证数据唯一性:唯一索引可以强制保证列中的数据唯一性,适合唯一性要求的字段。
- 提升查询效率:唯一索引在查询时会加速查找,因为其唯一性可以快速定位记录,减少扫描。
- 减少重复数据:唯一索引可有效防止重复数据,维护数据库完整性。
缺点
- 影响写入操作性能:在插入、更新时,唯一索引需要额外检查唯一性,增加了写入操作的开销。
- 占用存储空间:唯一索引占用额外的存储空间,对于数据量增大的表会占用更多的磁盘资源。
- 只允许一个NULL :大多数情况下,每个唯一索引字段只允许一个
NULL
,在某些情况下会增加复杂度。
7.唯一索引的使用和优化
最后索引可显着着提升查询性能,但不当使用会增加仓库仓储和维护成本,以下是一些使用和优化建议:
7.1 为常用查询和需要唯一性的字段创建唯一索引
唯一索引应优先用于在查询中重复使用的字段,以及有唯一性需求的字段,例如用户名、身份证号等。
7.2 避免在间隙更新的字段上使用唯一索引
由于唯一索引在插入和更新时需要进行唯一性检查,间隔更新的字段不适合创建唯一索引,避免影响写入性能。
7.3 使用复合唯一索引优化组合查询
对于多个字段组合有唯一性要求的情况(如订单号和商店ID的组合),可以创建复合唯一索引。这既能满足唯一性要求,也能加速组合查询。例如:
ALTER TABLE orders ADD UNIQUE (order_id, store_id);
8.唯一索引的使用注意事项
- 选择合适的字段:唯一索引适合那些在查询中频繁使用、需要唯一性约束的字段。
- 注意写性能影响:在高并发写入的场景中,唯一索引会增加写入开销,应避免不必要的唯一索引。
- 避免在多NULL字段上使用 :在MySQL中,唯一索引字段通常只允许一个
NULL
值,对于可以为空的字段不建议设置唯一索引。 - 检查索引使用情况 :可以使用
EXPLAIN
语句查看查询时是否使用了唯一索引,以确保索引设计有效: - EXPLAIN SELECT * FROM users WHERE email = 'john@example.com';
9.唯一索引的性能分析
唯一索引在查询性能上表现良好,可以使用EXPLAIN
来确认查询是否使用了唯一索引,并分析性能。通过合理规划唯一索引的创建和使用,可以有效提升数据库的查询速度,同时保证数据的唯一性和完整性性。
4.全文索引
全文索引(Fulltext Index)是一种用于加速文本字段搜索的索引类型,主要用于对大段文本(如文章内容、产品描述等)中的关键字进行快速查找。全文索引适合处理复杂的全文搜索需求,例如在长文本中查找包含特定词汇的记录。MySQL中,全文索引支持分词搜索和布尔模式搜索,能够在大数据量的情况下显着提高查询速度。
1. 全文索引
- 适用于大文本字段 :全文索引通常用于
CHAR
、VARCHAR
和TEXT
类型的列。 - 分词搜索:全文索引支持分词,能够以词为单位进行搜索,而不是简单的字符串匹配。
- 布尔模式:全文索引支持布尔模式,可以使用逻辑运算符组合多个关键字进行复杂查询。
- 支持自然语言模式:全文索引支持自然语言查询,能够自动识别并排序最相关的记录。
- InnoDB和MyISAM支持 :MySQL的
InnoDB
和MyISAM
存储引擎都支持全文索引,虽然实现方式有所不同。
2. 全文索引的作用
全文索引的作用在于提升大文本字段的查询效率,尤其是对于包含大量文本的列,全文索引可以在大量数据中快速查找到指定词汇的行,从而显着提升搜索速度。常见的应用场景包括:博客关键词文章、产品说明、评论系统等长文本数据的搜索。
3. 全文索引的创建方式
在MySQL中,可以通过以下方式创建全文索引:
3.1 在创建表时定义全文索引
可以在CREATE TABLE
语句中直接定义全文索引:
CREATE TABLE articles (
id INT PRIMARY KEY,
title VARCHAR(255),
content TEXT,
FULLTEXT (title, content) -- 为title和content字段创建全文索引
);
3.2 在已有表上添加全文索引
可以使用ALTER TABLE
语句为现有表添加外部索引:
ALTER TABLE articles ADD FULLTEXT (content); -- 为content字段添加全文索引
3.3 使用CREATE FULLTEXT INDEX
语句创建全文索引
可以使用CREATE FULLTEXT INDEX
语句为表的指定字段创建全文索引:
CREATE FULLTEXT INDEX idx_fulltext_content ON articles (content);
4. 全文索引的使用示例
创建完全文索引后,就可以在SELECT
查询中使用MATCH ... AGAINST
语句来进行全文搜索。
4.1 自然语言模式搜索
在自然语言模式下,MySQL会根据查询词自动匹配最相关的记录,并按相关度排序。可以使用MATCH(column_name) AGAINST ('search_term' IN NATURAL LANGUAGE MODE)
来实现:
SELECT * FROM articles
WHERE MATCH(title, content) AGAINST('database optimization' IN NATURAL LANGUAGE MODE);
上面的查询将检索title
和content
字段中包含"数据库优化"字样的记录,并按相关性排序。
4.2 布尔模式搜索
在布尔模式下,可以使用逻辑接口来实现复杂的查询。常用的布尔接口包括:
+
:必须包含的关键字-
:必须不包含的关键字>
<
:提升或降低关键字的相关度*
:通配符,匹配该词为出口的内容
以下是布尔模式的示例:
SELECT * FROM articles
WHERE MATCH(title, content) AGAINST('+database -optimization' IN BOOLEAN MODE);
该查询表示查找title
和content
中包含"数据库"但不包含"优化"的记录。
4.3 使用全文索引进行多关键词查询
通过MATCH
语句中的AGAINST
,可以指定多个关键词。查询的相关性会根据多个关键词进行匹配。例如:
SELECT * FROM articles
WHERE MATCH(content) AGAINST('MySQL indexing techniques');
MySQL会返回包含所有或部分关键词的记录,并根据匹配的词数和位置排序结果的相关性。
5. 全文索引的存储结构和工作原理
MySQL的全文索引在不同的存储引擎中实现方式不同:
- MyISAM:使用倒排索引来存储全文索引数据。这种方法类似于搜索引擎中使用的倒排索引,可以快速查找到包含特定词的文档。
- InnoDB:在5.6版本及以上支持全文索引,利用了B+树和倒排索引的混合结构,使得在大数据量的情况下具有更好的性能。
MySQL的全文索引对文本内容进行分词、删除缺失词(如常见的介词、连接词等),并计算文档中关键词的位置、词频等信息,以便在查询时进行匹配和计算相关性。
6. 全文索引的优缺点
优点
- 加速文本查询:全文索引能够显着提高对长文本字段的关键词查询速度。
- 相关性排序:MySQL全文索引支持按相关性排序,查询结果更符合用户需求。
- 支持布尔查询:布尔模式可以使用逻辑接口,支持复杂的查询逻辑。
- 降低查询成本:在不使用全文索引的情况下,长文本字段的关键词查询可能导致全表扫描,全文索引减少了扫描的数据量。
缺点
- 占用大量存储空间:全文索引需要存储大量的词频、位置信息,因此占用的存储空间增大。
- 不支持部分字符匹配 :全文索引不支持
LIKE
的部分字符匹配,只能以词为单位进行匹配。 - 写入成本较高:在插入、更新数据时,MySQL 需要重建索引中的词信息,因此写入速度较慢。
- 语言依赖:MySQL全文索引依赖于分词算法,效果较适合中文等西方语言,对于中文、日文等语言的分词效果较差。
7. 全文索引的使用和优化
为了让全文索引更加高效,可以根据需求进行如下优化:
7.1 使用适合的存储引擎
在MySQL 5.6及更高版本中,InnoDB
并且MyISAM
都支持全文索引。InnoDB
在处理大数据量时有更好的性能和事务支持,因此推荐使用InnoDB
。
7.2 设置ft_min_word_len
参数
ft_min_word_len
参数控制MySQL的全文索引分词最小长度。默认情况下,MySQL会忽略长度小于4的字典。如果数据中有大量短词,可以降低该参数值:
SET GLOBAL ft_min_word_len = 3;
但降低该参数值会增加索引的存储需求。
7.3 使用EXPLAIN
分析性能
可以通过EXPLAIN
语句检查全文查询是否使用了索引,以及查询的执行计划:
EXPLAIN SELECT * FROM articles
WHERE MATCH(title, content) AGAINST('MySQL optimization' IN NATURAL LANGUAGE MODE);
7.4 根据需求选择查询模式
自然语言模式适合通用的关键词查找,而布尔模式适合更复杂的查询需求,选择合适的模式可以提升查询效率。
7.5 定期重建指数
对于动态变化饱和的表,定期重建索引可以保持索引的有效性和性能:
OPTIMIZE TABLE articles;
8. 全文索引的使用注意事项
- 适合在大文本字段上使用 :索引适合在长文本字段(如
TEXT
字段)上使用,不适合短字段。 - 避免分区更新:在数据更新分区的场景中,全局索引的重建成本最高,应尽量避免分区修改使用分区索引的索引。
- 语言影响 :MySQL的全文索引对中文等西方语言分词效果较好,但对中文等语言分词效果有限,可以考虑使用第三方工具,例如
Elasticsearch
。
9. 综合索引的性能测试
MySQL 全文索引在大数据量下的查询速度明显快于常规的LIKE
查询,通过可以在数据表上创建全文索引,利用MATCH ... AGAINST
语法实现高效的关键词查询。在性能测试中,通过选择合理的参数和模式,优化索引的性能,并保证满足应用场景的需求。
5.聚集索引
聚集索引 (Clustered Index),又称聚簇索引,是一种按照主键顺序组织数据的索引方式。聚集索引将数据和索引存储在一起,使数据按照索引的顺序存储在磁盘上,查询主键或按顺序访问数据时效率更高。
在MySQL中,InnoDB
存储引擎默认保留主键作为聚集索引,每个表只能有一个聚集索引。如果表没有显式主键,InnoDB会自动选择一个唯一非且空的列来创建聚集索引;如果没有这样的列,InnoDB会创建一个隐式的行ID列作为聚集索引。
1.聚集索引
- 数据和索引存储在一起:聚集索引将索引节点和数据行放在一起存储,叶子节点包含完整的数据行。
- 按主键顺序存储:数据按照磁盘上的主键顺序物理存储,使得顺序查找和范围查询更快。
- 每个表只能有一个聚集索引:由于数据行只能有一个物理顺序,每个表只能有一个聚集索引。
- 对主键查询性能优化显着:因数据行和索引在相同结构中,主键查询会非常快。
2. 聚集索引的作用
聚集索引的主要作用是加速主键和范围查询。聚集索引按主键依次排序数据行,按主键范围查询时不需要扫描整表,效率高。另外,聚集索引也有助于加速与主键有关的重复操作。由于数据与索引一体化存储,可以减少IO操作和查找次数。
3.聚集索引的创建方式
在MySQL的InnoDB存储引擎中,聚集索引会自动基于主键创建。因此,通过主键定义表时,MySQL会默认创建聚集索引。
3.1 在创建表时定义主键(聚集索引)
可以通过CREATE TABLE
语句在创建表时定义主键索引。主键即为聚集索引:
CREATE TABLE articles (
id INT PRIMARY KEY,
title VARCHAR(255),
content TEXT,
FULLTEXT (title, content) -- 为title和content字段创建全文索引
);
3.2 为已有表添加主键(聚集索引)
若表没有主键,可以通过ALTER TABLE
语句添加主键,这样会自动创建聚集索引:
ALTER TABLE students ADD PRIMARY KEY (id); -- 将id字段设为主键,创建聚集索引
4. 聚集索引的使用示例
4.1 基于主键的
由于聚集索引使数据按主键顺序存储,基于主键的查询效率非常高。以下查询可以直接利用聚集索引:
SELECT * FROM students WHERE id = 1;
4.2 范围查询
聚集索引按主键顺序存储数据,范围查询可以快速找到符合条件的连续数据行,而不需要扫描全表:
SELECT * FROM students WHERE id BETWEEN 1 AND 10;
5.聚集索引的存储结构
在引擎中聚集索引InnoDB
使用B+树存储结构。B+树的特点如下:
- 叶子节点存储数据行:叶子节点包含完整的数据行,通过依次主键查找到叶子节点时,可以直接读取数据。
- 按主键顺序存储:数据按照主键顺序存储在B+树的叶子节点中,使得主键查询和范围查询效率更高。
- 叶子节点存储的索引值:非叶子节点存储是索引键值和指向子节点的指针,从而快速查找数据。
6. 聚集索引的优缺点
优点
- 提升主键查询和范围查询效率:聚集索引将数据按主键排序存储,主键和范围查询会更快。
- 减少IO操作:数据行和索引间的存储,查询时减少了数据和索引间的随机访问。
- 数据顺序存储:聚集索引按主键排序数据,形成数据排序,进行范围查询和排序查询。
缺点
- 插入和更新性能影响:索引聚集按主键顺序存储数据,在因此插入新记录时需要调整顺序,尤其是在主键不自增或无序情况下,插入性能会受到影响。
- 二级索引存储主键值:在非聚集索引(即二级索引)中,叶子节点聚集是索引的主键值,而不是数据的物理地址。二级索引的查找依赖主键,增加了索引维护成本。
- 页面分裂问题:如果新插入的主键值在已有数据之间,可能会导致页面分裂,影响性能。
7. 聚集索引的使用和优化
聚集索引在数据管理中有重要的作用和使用技巧:
7.1 使用顺序的自增主键作为聚集索引
使用自增主键作为聚集索引可以有效减少页面分裂,提高写入性能。自增主键保证每次插入的数据都添加在表的补充,调整避免数据顺序和间隔的页面分裂。
CREATE TABLE employees (
employee_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50),
department VARCHAR(50)
);
7.2 避免在间隙更新的列上使用聚集索引
聚集索引按主键顺序存储,如果主键经常更改,底部会导致大量的数据移动,影响性能。因此不建议在需要更新的列上使用聚集索引。
7.3 使用适合的存储引擎
InnoDB
存储引擎支持聚集索引,可以更好地利用聚集索引提升查询和存储性能。如果主要需求是事务支持和主键查询,推荐使用InnoDB
。
7.4 定期进行表优化
当数据间歇插入、删除时,聚集索引的物理顺序可能会影响性能。通过OPTIMIZE TABLE
语句可以定期整理表,保持聚集索引的顺序和效率:
OPTIMIZE TABLE students;
8.聚集索引的性能测试
聚集索引对基于主键的查询和范围查询性能提升显着。可以通过以下方式测试聚集索引的性能:
- 在一张有大量数据的表上进行主键查询、范围查询,测量响应时间。
- 观察聚集索引在不同数据量情况下的表现,并与非聚集索引或全表扫描的查询速度对比。
聚集索引在大数据量下性能优势明显,尤其是在主键查询和范围查询场景中,可以显着降低查询时间和IO消耗。
9. 聚集索引的使用注意事项
- 表中只能有一个聚集索引:由于聚集索引按数据顺序决定了物理顺序,因此,每个表只能有一个聚集索引。
- 不关闭建议更新主键:如果主键发生变化会导致大量数据移动,降低性能。
- 二级索引依赖聚集索引:在非主键索引(如普通索引、唯一索引)中,叶子节点存储是主键值除物理地址,二级索引查询后还需查找聚集索引。
6.非聚集索引
非聚集索引 (非聚集索引),第二级索引 或辅助索引 ,是一种将索引和数据存储分离的索引结构。与聚集索引不同,非聚集索引的叶子节点不包含完整的数据行,而是存储了索引列的值以及指向数据行的引用(例如主键值或数据行的指针)。在MySQL的InnoDB
存储引擎中,非聚集索引指向聚集索引中的主键,使得在数据时需要查找一个"回表"操作可以获得完整的数据行。
聚集非索引适用于需要提高查询速度,但不需要按主键顺序存储的场景。它通常用于加速在某些列上的查询和排序操作。
1. 非聚集索引市场
- 索引与数据分离:非聚集索引的叶子节点只存储索引列的值和指向数据行的指针或主键,不包含完整数据行。
- 每个表可以有多个非聚集索引:与聚集索引不同,非聚集索引不依赖数据的物理存储顺序,因此一个表可以拥有多个非聚集索引。
- 加速查询和排序:非聚合索引可以有效支持某些特定列的查询、排序和分组操作。
- 回表操作:非聚集索引查找到对应索引值后,通常还需要通过聚集索引或数据行指针重新查找数据,即"回表"。
2. 非聚集索引的作用
非聚集索引的主要作用是加速在非主键列上的查询。通过在常用查询条件的列上创建非聚集索引,可以显着提升查询效率,减少全表扫描的次数。它特别适合一些基于非主键的列查找和排序需求。
3.非聚集索引的创建方式
在MySQL中,可以使用以下几种方式创建非聚集索引:
3.1 在创建表时定义非聚集索引
在CREATE TABLE
语句中可以直接定义非聚集索引:
CREATE TABLE employees (
employee_id INT PRIMARY KEY, -- 主键是聚集索引
name VARCHAR(50),
department VARCHAR(50),
INDEX idx_department (department) -- 在department列上创建非聚集索引
);
3.2 在已有表上添加非聚集索引
可以使用ALTER TABLE
语句为现有表添加非聚集索引:
ALTER TABLE employees ADD INDEX idx_name (name); -- 在name字段上创建非聚集索引
3.3 使用CREATE INDEX
语句创建非聚集索引
可以使用CREATE INDEX
语句为表的指定字段创建非聚集索引:
CREATE INDEX idx_department ON employees (department);
4. 非聚集索引的使用示例
4.1 基于非聚集索引的查询
聚集非索引可以基于特定列的查询显着加速,例如以下查询:
SELECT * FROM employees WHERE department = 'Sales';
在department
字段上创建非聚集索引后,MySQL 将使用该索引快速定位包含'Sales'
的记录,而不需要扫描整个表。
4.2 使用非聚集索引进行排序
非聚集索引也可以优化ORDER BY
语句的执行效率。以下示例按department
列排序:
SELECT * FROM employees ORDER BY department;
如果department
字段上没有聚集索引,MySQL可以利用索引直接按顺序提取记录,而不需要进行额外的排序操作。
5.非聚集索引的存储结构和工作原理
非聚集索引在InnoDB
引擎中同样基于B+树结构,非聚集索引引用的叶子节点存储索引列值和指向数据行的。
在InnoDB中,非聚集索引的工作机制如下:
- 索引叶子节点:索引节点存储的是列的值和指向数据行的引用。对于InnoDB,引用为聚集索引的主键值。
- 回表操作:非聚集索引找到对应索引值后,还需要通过主键值在聚集索引中定位数据行,完成"回表"操作。
- 支持多列索引:MySQL支持在列上创建复合非聚集多个索引,以加速多条件查询。
6.不聚集索引的优点
优点
- 加速多列查询:非聚集索引可以在非主键列上加速查询,提高查询速度。
- 支持多个索引:一个表可以拥有非聚集索引,可以加速多个不同列的查询需求。
- 支持高效排序和分组 :在索引列上执行
ORDER BY
和GROUP BY
操作时可以利用索引提高效率。
缺点
- 增加存储空间:非聚集索引需要额外的存储索引值和主键或行指针,因此会占用额外的磁盘空间。
- 回表成本:查找时需要二次访问数据行(即回表操作),增加了IO操作。
- 更新和删除操作影响性能:在非聚集索引列上执行更新和删除操作时,MySQL需要维护索引结构,会增加维护成本。
7. 非聚集索引的使用和优化
7.1 选择适当的列进行索引
在高频查询或条件查询的列上创建非聚集索引,可以显着提升查询效率。建议避免在高频更新的列上创建非聚集索引,因为索引维护成本高。
7.2 使用复合索引优化多条件查询
如果查询中涉及多列,可以使用复合索引。例如,在department
和name
字段上创建复合非聚集索引,以加速多条件查询:
CREATE INDEX idx_department_name ON employees (department, name);
多条件时,MySQL可以利用复合索引加速查询,尤其是在符合"最左出口查询原则"时。
7.3 定期优化索引结构
对间隙插入、更新的表,不聚集索引可能会导致索引结构不均匀。可以使用OPTIMIZE TABLE
语句定期重建和整理索引:
OPTIMIZE TABLE employees;
8.不聚集索引的性能测试
非聚集索引适用于分区查询的列,索引范围查询、排序、分组等操作都有明显的性能提升。可以通过以下方法进行性能测试:
- 在一张大数据量的表上添加非聚集索引,比较查询的响应时间。
- 使用
EXPLAIN
分析查询计划,确认查询是否在使用非聚集索引。
以下示例可以帮助查看查询性能和索引的使用情况:
EXPLAIN SELECT * FROM employees WHERE department = 'Sales';
输出的查询计划中若包含Using index
,表明查询中使用了非聚集索引。
9. 不聚集索引的使用注意事项
- 避免在小表上使用:小表中的记录数量少,全表扫描的成本较低,非聚集索引的性能提升不明显。
- 选择高选择性的列:在选择性(不重复值多)高的列上创建非聚集索引效果更好,因为选择性高的索引能够更准确地过滤数据。
- 合理选择复合索引顺序:在复合索引中,列的顺序会影响查询的效果,应优先选择查询中最常用的列作为复合索引的第一个字段。
7.索引覆盖
索引覆盖(Covering Index)是指在查询过程中,查询所需的所有列都包含在索引中,因而不需要回表(访问数据表的记录)即可完成查询。换句话说,索引覆盖的查询过程直接从索引中获取数据,避免了访问实际数据行的操作。索引覆盖能够显着提高查询性能,是一种常用的MySQL查询优化方法。
索引覆盖的最大优势在于提高查询效率,因为它可以减少磁盘I/O操作。索引覆盖通常与非聚集索引结合使用,但在某些情况下,聚集索引也可以实现索引覆盖。
1. 索引覆盖概念
索引覆盖的查询是一个"覆盖索引查询"(Covering Index Query),在MySQL中称为"覆盖索引"。当一个索引能够"覆盖"查询中的所有字段时,即索引中包含查询中涉及的所有列,那么查询就可以在索引内部完成,而消耗回表操作。
2. 索引覆盖优势
- 减少I/O操作:避免回表查找数据,直接从索引中获取数据,显着减少磁盘I/O。
- 提高查询效率:从索引中直接获取数据通常比从数据行中更快地提取数据。
- 降低数据表的锁竞争:索引覆盖可以减少对实际数据表的访问,减少锁的竞争,提高并发性能。
3. 索引覆盖的实现条件
要实现索引覆盖查询,需要满足以下条件:
- 查询中所需的所有列都必须包含在某个索引中。
- MySQL优化器选择了该索引作为查询执行计划中的最佳索引。
通常,索引覆盖使用的是非聚集索引,但在少数情况下,聚集索引也可以实现索引覆盖(例如,仅查询主键列时)。
4. 索引覆盖的创建方式
4.1 在单列查询上实际索引覆盖
对于单列查询,可以在该列上创建索引,从而实现索引覆盖:
CREATE TABLE employees (
employee_id INT PRIMARY KEY,
name VARCHAR(50),
department VARCHAR(50),
salary DECIMAL(10, 2),
INDEX idx_name (name) -- 在 name 列上创建索引
);
-- 查询仅使用 name 列
SELECT name FROM employees WHERE name = 'Alice';
在上面的查询中,name
列上的索引idx_name
可以完全覆盖查询,无需回表。
4.2 在多列查询上实际索引覆盖(复合索引)
在多列查询中,可以通过创建复合索引来实现索引覆盖:
CREATE INDEX idx_name_department ON employees (name, department);
-- 查询只涉及 name 和 department 列
SELECT name, department FROM employees WHERE name = 'Alice';
在查询中,idx_name_department
复合索引包含了上述name
和department
列,因此查询可以直接从索引获取数据而抽取回表。
5. 索引覆盖的使用示例
以下示例展示了如何利用索引覆盖来优化查询:
示例 1:单列索引覆盖查询
-- 假设有索引 idx_department 覆盖 department 列
CREATE INDEX idx_department ON employees (department);
-- 查询只涉及 department 列
SELECT department FROM employees WHERE department = 'Sales';
在该查询中,department
列上有索引idx_department
,该索引包含了查询所需的所有数据,因此可以直接使用索引覆盖,避免了回表操作。
示例2:复合索引覆盖查询
-- 假设有复合索引 idx_name_salary 覆盖 name 和 salary 列
CREATE INDEX idx_name_salary ON employees (name, salary);
-- 查询只涉及 name 和 salary 列
SELECT name, salary FROM employees WHERE name = 'Alice';
在该查询中,复合索引idx_name_salary
包含了name
和salary
列的数据,因此查询可以直接从索引中获取所有需要的数据。
6.索引覆盖的查询性能分析
可以通过EXPLAIN
语句来查看查询计划,确认查询是否在使用索引覆盖。如果查询中包含Using index
关键字,则表明该查询使用了索引覆盖。
EXPLAIN SELECT name, department FROM employees WHERE name = 'Alice';
输出中如果包含Using index
,则说明该查询使用了索引覆盖。
7. 索引覆盖的优缺点
优点
- 查询性能显着提升:索引覆盖减少了回表操作,直接从索引中读取数据,查询效率显着提高。
- 降低IO和CPU消耗:索引覆盖直接从索引获取数据,降低了磁盘I/O开销和CPU使用率。
- 更高的并发性能:减少了对数据页的访问,索引覆盖减少了锁争用,提高了查询并发性。
缺点
- 占用额外的存储空间:为了实现索引覆盖,需要创建多列复合索引,这会消耗额外的磁盘空间。
- 索引维护成本增加:多列索引会增加插入、更新和删除操作的索引成本维护,尤其是在需要清理的数据列上不适合修改创建大量覆盖索引。
- 无法获取大字段 :对于长文本或大字段(如
TEXT
和BLOB
),不适合创建索引覆盖查询,因为会占用大量存储空间和索引维护资源。
8. 索引覆盖的优化建议
8.1 选择高频查询频率的列进行索引覆盖
在间隙进行查询的列上创建索引覆盖可以最大化提升查询性能。例如:
CREATE INDEX idx_name_department_salary ON employees (name, department, salary);
8.2 避免在大字段或低索引列上创建索引覆盖
大字段(如TEXT
或BLOB
)或低索引的列不适合索引覆盖,因为这些列占用存储空间大且查询过滤效果差。
8.3 使用复合索引实现多列覆盖
对于多列查询,可以使用复合索引来实现更高效的索引覆盖,例如:
CREATE INDEX idx_dept_salary ON employees (department, salary);
9. 索引覆盖的常见变量区
- 索引覆盖并不是针对所有查询:并非所有查询都通过索引覆盖优化,尤其是涉及大字段、低索引列或少量数据的表。
- 覆盖索引并不是万能的:索引覆盖可以提高查询性能,但会增加存储和维护成本。创建索引时要平衡查询频率与更新开销。
- 并非所有复合索引都适用覆盖索引:复合索引的列顺序影响覆盖索引效果,建议按最常用的查询列的顺序来创建复合索引。
10. 索引覆盖的总结
索引覆盖是MySQL查询优化的一个重要手段,通过将查询所需的所有数据放入索引结构中,可以有效提升查询性能,减少I/O操作。合理设计覆盖索引可以最大化查询效率,但需要平衡索引的存储和维护成本。以下是索引覆盖的一些关键总结:
- 选择合适的列:在查询间隙的列上创建索引覆盖,减少全表扫描。
- 复合索引顺序:创建复合索引时,将最常用的查询列放在前面,优化查询效果。
- 避免大字段:不建议在长文本类型或大字段上使用覆盖索引,避免存储浪费。
5. 索引的优化
MySQL在查询优化时,会根据数据量、查询条件、表的结构等情况选择是否使用索引。以下是一些常见的索引优化建议:
5.1 使用"覆盖索引"
覆盖索引是指查询的所有字段都被索引包含,不需要额外的扫描数据行。例如:
CREATE INDEX idx_name_age ON employees (name, age);
SELECT name, age FROM employees WHERE name = 'Alice';
在这个查询中,idx_name_age
索引包含了所有需要的数据,查询可以直接从索引中返回结果。
5.2 避免低索引字段创建索引
低焦距索引的视野(如性别)创建的效果不明显。低焦距,索引的加速效果较好。
5.3 使用"最左出口原则"优化组合索引
在组合索引中,应把常用且具有高索引的字段放在最左侧。
6. 使用索引的优点总结
优点:
- 快速数据检索:索引允许数据库更快速地查找到特定的数据。
- 排序加速 :使用索引可以加速
ORDER BY
语句。 - 避免重复值:唯一索引和主键索引可以避免重复数据。
缺点:
- 占用空间:索引会增加表的存储空间需求。
- 增减删减头部:插入、删除、更新数据时,索引需要重建或更新,会增加操作成本。
7. 索引相关的MySQL查询性能分析工具
MySQL提供了来EXPLAIN
关键字查看查询语句的执行计划以及是否使用了索引:
EXPLAIN SELECT * FROM employees WHERE department_id = 3;
从左至右,性能由差到好
1.ALL: 扫描全表
2.index: 扫描全部索引树
3.range:扫描部分索引,索引范围扫描,对索引的扫描开始于某一点,返回匹配值域的行,常见于between、<、>等的查询4.ref: 使用非唯一索引或非唯一索引前缀进行的查找,不是主键或不是唯一索引
(eq_ref和const的区别:)
5.eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描
6.const, system:单表中最多有一个匹配行,查询起来非常迅速,例如根据主键或唯一索引查询。system是const类型的特例,当查询的表只有一行的情况下,使用system。
7.NULL:不用访问表或者索引,直接就能得到结果
8.结语:
在MySQL的世界里,索引就像数据库的"秘密捷径",让数据飞速到达。通过掌握主键索引、唯一索引、普通索引到高级的全索引、聚集索引、非聚集索引,再到索引覆盖这些"神奇工具",我们就像装备了一套整套数据库加速装置
终点索引有自己独特的角色和用法:有的专注于去重,有的熟练范围查询,还有的可以覆盖全场,避免"回表绕路"。合理地使用它们,才能够查询速度翻倍,还能减少磁盘和CPU的"体力消耗",为数据库高效运行保驾护航。
当然,指标虽然好,也有它的小脾气:多了容易"站地儿",用错了物种"负重爬坡"。所以要记住------"用得其所、各司其职",才能真正享受索引带来的
在MySQL这条路上,有索引的陪伴,我们前面行的速度会更快更轻松。愿大家在这条索引路上越走越欢快,数据库跑得飞快!