文章目录
MySQL索引
索引是一种数据结构,用于快速查找数据库表中的记录。在MySQL中,索引类似于书的目录,通过索引可以快速定位到表中的某一行数据,而不需要扫描整个表。索引存储了索引列的值以及这些值对应的行的物理地址(或称为行指针)。
- 排序的列表:索引是一个按索引列排序的列表。
- 物理地址:索引条目中包含了索引列的值和包含该值的行的物理地址。
- 加速查询:使用索引可以加速查询操作,因为数据库系统可以利用索引快速定位到所需的数据行。
索引的概念
- 定义:索引是一个排序后的列表,其中存储了索引值以及这些值对应数据行的物理地址。
- 作用:通过索引,数据库可以快速定位到所需数据行,避免全表扫描,从而加速查询。
- 类比:索引类似于书籍的目录,通过目录中的页码可以迅速找到内容。
- 排序方式:索引是基于表中一列或多列的值进行排序的。
- 目的:创建索引主要是为了加快数据查找和排序速度。
索引的作用
- 加速查询:合适的索引能显著提高数据库查询速度。
- 大数据量优势:在处理大型表或多表查询时,索引的效果尤为明显。
- 降低成本:减少IO操作和排序成本。
- 数据唯一性:通过唯一性索引确保数据的唯一性。
- 连接加速:加快表与表之间的连接操作。
- 分组排序优化:在执行GROUP BY和ORDER BY操作时提高效率。
- 数据恢复性能:在搜索和恢复数据时提升性能。
索引的副作用
尽管索引带来了诸多好处,但也有一些潜在的副作用需要注意:
- 空间消耗:索引占用额外的磁盘空间。
- MyISAM:索引文件与数据文件分离。
- InnoDB:数据文件本身就是索引文件(聚集索引)。
- 更新开销:更新包含索引的表比更新无索引的表更耗时,因为需要同时更新索引。
- 选择不当的索引:如果索引选择不当,可能会导致查询性能下降,甚至不如没有索引的情况。
创建索引的原则依据
创建索引时,需要遵循一些原则以确保索引的有效性:
- 主键和外键:主键和外键列通常应该建立索引,因为它们经常用于查询和连接操作。
- 记录数超过300行的表:对于包含大量记录的表,应该考虑建立索引以加速查询。
- 连接字段:在经常用于连接(JOIN)操作的字段上建立索引。
- 唯一性差的字段:唯一性差的字段(如性别、布尔值等)不适合建立索引,因为索引的选择性较差。
- 更新频繁的字段:更新频繁的字段不适合建立索引,因为索引的更新开销较大。
- WHERE子句中的字段:经常出现在WHERE子句中的字段,特别是大表的字段,应该建立索引。
- GROUP BY和ORDER BY字段:在经常进行GROUP BY和ORDER BY操作的字段上建立索引。
- 选择性高的字段:索引应该建在选择性高的字段上,即不同值较多的字段。
- 小字段:索引应该建在小字段上,因为大字段(如长文本)的索引开销较大。
示例
假设我们有一个名为employees
的表,包含以下字段:id
(主键)、name
(姓名)、age
(年龄)、department
(部门)和salary
(薪水)。以下是一些可能的索引策略:
- 主键索引:在
id
字段上创建主键索引(通常是自动创建的)。 - 唯一索引:如果
email
字段是唯一的,可以在email
字段上创建唯一索引。 - 组合索引:在经常一起查询的字段上创建组合索引,如
(department, age)
。 - 全文索引:如果需要在
name
或description
等文本字段上进行全文搜索,可以创建全文索引。
创建索引的SQL语句示例:
-- 创建主键索引(通常自动创建)
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(100),
age INT,
department VARCHAR(50),
salary DECIMAL(10, 2)
);
-- 创建唯一索引
CREATE UNIQUE INDEX idx_email ON employees(email);
-- 创建组合索引
CREATE INDEX idx_dept_age ON employees(department, age);
-- 创建全文索引(仅适用于MyISAM和InnoDB引擎的CHAR、VARCHAR和TEXT字段)
CREATE FULLTEXT INDEX idx_name ON employees(name);
MySQL 索引分类与创建
索引分类
- 普通索引
- 最基本的索引类型,没有唯一性限制,允许有空值。
- 创建方式:
- 直接创建:
CREATE INDEX 索引名 ON 表名 (列名[(length)]);
- 修改表结构:
ALTER TABLE 表名 ADD INDEX 索引名 (列名);
- 创建表时指定:
CREATE TABLE 表名 (字段1 数据类型, ..., INDEX 索引名 (列名));
- 直接创建:
- 唯一索引
- 与普通索引类似,但要求索引列的值必须唯一。
- 允许有空值,但空值不参与唯一性比较。
- 创建方式:
- 直接创建:
CREATE UNIQUE INDEX 索引名 ON 表名(列名);
- 修改表结构:
ALTER TABLE 表名 ADD UNIQUE 索引名 (列名);
- 创建表时指定:
CREATE TABLE 表名 (字段1 数据类型, ..., UNIQUE 索引名 (列名));
- 直接创建:
- 主键索引
- 特殊的唯一索引,必须指定为“PRIMARY KEY”。
- 一个表只能有一个主键索引,不允许有空值。
- 创建方式:
- 创建表时指定:
CREATE TABLE 表名 ([...], PRIMARY KEY (列名));
- 修改表结构:
ALTER TABLE 表名 ADD PRIMARY KEY (列名);
- 创建表时指定:
- 组合索引(多列索引)
- 在多列上创建的索引,查询时满足最左前缀原则。
- 创建方式:
CREATE INDEX 索引名 ON 表名 (列名1, 列名2, ...);
- 全文索引(FULLTEXT)
- 用于全文检索,适合在CHAR、VARCHAR或TEXT类型的列上创建。
- MySQL 5.6版本之前仅支持MyISAM引擎,之后InnoDB引擎也支持。
- 创建方式:
- 直接创建:
CREATE FULLTEXT INDEX 索引名 ON 表名 (列名);
- 修改表结构:
ALTER TABLE 表名 ADD FULLTEXT 索引名 (列名);
- 创建表时指定:
CREATE TABLE 表名 (字段1 数据类型, ..., FULLTEXT 索引名 (列名));
- 直接创建:
索引创建示例
针对member
表,以下是各种索引的创建示例:
-- 创建普通索引
CREATE INDEX name_index ON member (name);
-- 修改表结构创建普通索引
ALTER TABLE member ADD INDEX phone_index (phone);
-- 创建表时指定普通索引
CREATE TABLE member_with_index (
id INT(10),
name VARCHAR(10),
cardid INT(18),
phone INT(11),
address VARCHAR(50),
remark TEXT,
INDEX address_index (address)
);
-- 创建唯一索引
CREATE UNIQUE INDEX cardid_index ON member (cardid);
-- 修改表结构创建唯一索引
ALTER TABLE member ADD UNIQUE unique_name_index (name);
-- 创建表时指定主键索引(注意:主键索引通常是在创建表时指定的)
CREATE TABLE member_with_pk (
id INT(10) PRIMARY KEY,
name VARCHAR(10),
cardid INT(18),
phone INT(11),
address VARCHAR(50),
remark TEXT
);
-- 或者修改表结构添加主键索引
ALTER TABLE member ADD PRIMARY KEY (id);
-- 创建组合索引
CREATE INDEX name_phone_index ON member (name, phone);
-- 创建全文索引
CREATE FULLTEXT INDEX remark_index ON member (remark);
-- 修改表结构创建全文索引
ALTER TABLE member ADD FULLTEXT fulltext_remark_index (remark);
索引使用注意事项
- 选择合适的列:为经常出现在
WHERE
子句、JOIN
操作、ORDER BY
和GROUP BY
子句中的列创建索引。 - 避免过多索引:虽然索引能加快查询速度,但也会增加写操作的开销(如插入、更新、删除)。因此,应根据实际需求合理控制索引数量。
- 考虑索引大小:对于大文本字段,创建索引可能会占用大量磁盘空间。因此,在创建索引时应权衡索引带来的性能提升和磁盘空间开销。
- 最左前缀原则:在使用组合索引时,应确保查询条件中的列顺序与索引中的列顺序一致,以充分利用索引。
- 全文索引限制:全文索引适用于模糊查询,但不适用于精确匹配。此外,全文索引的性能受多种因素影响,如索引大小、查询复杂度等。
索引查看与删除
-
查看索引:
使用SHOW INDEX FROM 表名;
或SHOW KEYS FROM 表名;
可以查看表中的索引信息。 -
删除索引:
- 直接删除索引:
DROP INDEX 索引名 ON 表名;
- 修改表方式删除索引:
ALTER TABLE 表名 DROP INDEX 索引名;
- 删除主键索引:
ALTER TABLE 表名 DROP PRIMARY KEY;
- 直接删除索引:
索引案例应用
假设我们为某商场创建一个会员卡系统,会员表包含信息如下:
- 会员编号(
id
):INT类型,主键。 - 会员姓名(
name
):VARCHAR(10)类型,普通索引。 - 会员身份证号码(
cardid
):VARCHAR(18)类型(注意原题中类型为INT(18)是不准确的,应为VARCHAR或CHAR类型),唯一索引。 - 会员电话(
phone
):INT(11)类型。 - 会员住址(
address
):VARCHAR(50)类型。 - 会员备注信息(
remark
):TEXT类型,全文索引(但需注意其适用性)。
创建表及索引的SQL语句如下:
CREATE TABLE member (
id INT(10) NOT NULL,
name VARCHAR(10),
cardid VARCHAR(18),
phone INT(11),
address VARCHAR(50),
remark TEXT,
PRIMARY KEY (id)
);
-- 创建普通索引
CREATE INDEX name_index ON member (name);
-- 创建唯一索引
CREATE UNIQUE INDEX cardid_index ON member (cardid);
-- 创建全文索引(注意:FULLTEXT索引在InnoDB引擎中可能不如MyISAM引擎效果好,且适用于长文本)
ALTER TABLE member ADD FULLTEXT (remark); -- 注意:MySQL 5.6+ InnoDB支持FULLTEXT,但效果因版本和配置而异
-- 或者在创建表时直接指定索引(但主键索引通常是在创建表时指定的)
-- CREATE TABLE member (
-- id INT(10) NOT NULL PRIMARY KEY,
-- name VARCHAR(10),
-- cardid VARCHAR(18) UNIQUE,
-- phone INT(11),
-- address VARCHAR(50),
-- remark TEXT,
-- FULLTEXT (remark) -- 注意:此语法可能因MySQL版本而异,且FULLTEXT通常不直接在CREATE TABLE中指定
-- );
-- 注意:上面的FULLTEXT直接在CREATE TABLE中指定的语法可能不被所有MySQL版本支持,因此推荐使用ALTER TABLE方式添加。
注意事项:
- 会员身份证号码应为VARCHAR或CHAR类型,因为身份证号码包含非数字字符(如最后的校验码可能是X)。
- FULLTEXT索引在短文本字段上的效果可能不如在长文本字段上。如果会员备注信息通常较短,可以考虑使用普通索引或组合索引来满足查询需求。
- 在实际应用中,应根据查询性能和数据特点选择合适的索引类型和数量。过多的索引会增加写操作的开销(如插入、更新、删除),因此应权衡索引带来的性能提升和磁盘空间开销。
要点总结
基础要点:
类别 | 描述 |
---|---|
定义 | 索引是一个排序的列表,包含索引字段的值和其对应的行记录数据所在的物理地址 |
作用 | 1. 加快表数据的查询速度(主要作用) 2. 对字段进行排序 3. 加快表与表的连接速度 4. 减少分组和排序的时间 |
副作用 | 1. 索引会额外占用磁盘空间 2. 更新包含索引的表会花费更多的时间 |
工作方式 | 没有索引:扫描全表后定位某行记录数据的位置 有索引:通过索引查询到行记录数据所在的物理地址,直接访问相应的行记录数据 |
创建索引的依据 | 1. 表的记录行数量较多(一般超过三五百行),且读操作多时创建索引 2. 建议创建索引的字段: - 主键字段 - 外键字段 - 多表连接的公共字段 - 唯一性较好的字段 - 不经常更新的字段 - where条件字段 - group by分组字段 - order by排序字段 - 短小的字段 3. 不建议创建索引的字段: - 唯一性较差的字段 - 更新太频繁的字段 - 大文本字段 |
命令:
以下是根据您提供的信息整理的关于索引类型的表格:
索引类型 | 创建方式 | 示例 | 注意事项/使用场景 | 删除方式 | 查看方式 |
---|---|---|---|---|---|
普通索引 | 1. create index 索引名 on 表名(字段(索引长度)); 2. alter table 表名 add index 索引名(字段); 3. create table 表名 (.... , index 索引名(字段)); |
create index idx_name on table_name(column_name); |
适用于一般查询优化 | drop index 索引名 on 表名; alter table 表名 drop index 索引名; |
show create table 表名; show index from 表名; show keys from 表名; |
唯一索引 | 1. create unique index 索引名 on 表名(字段); 2. alter table 表名 add unique 索引名(字段); 3. create table 表名 (.... , unique 索引名(字段)); |
create unique index idx_unique_name on table_name(column_name); |
保证字段值唯一性 | drop index 索引名 on 表名; (若索引是创建表时定义的,则无法直接删除,需重建表或删除后重建) |
同上 |
主键索引 | 1. alter table 表名 add primary key(字段); 2. create table 表名 (.... , primary key(字段)); |
alter table table_name add primary key(column_name); |
唯一且非空,用于标识表中的每一行 | alter table 表名 drop primary key; |
同上 |
多列组合索引 | 1. create index 索引名 on 表名(字段1, 字段2, ....); 2. alter table 表名 add index 索引名(字段1, 字段2, ....); (唯一和主键组合索引类似) |
create index idx_combo on table_name(column1, column2); |
适用于多个字段联合查询,需满足最左原则 | drop index 索引名 on 表名; alter table 表名 drop index 索引名; |
同上 |
全文索引 | 1. create fulltext index 索引名 on 表名(字段); 2. alter table 表名 add fulltext 索引名(字段); 3. create table 表名 (.... , fulltext 索引名(字段)); |
create fulltext index idx_fulltext_name on table_name(column_name); |
适用于文本字段的模糊查询 | drop index 索引名 on 表名; (若索引是创建表时定义的,则无法直接删除,需重建表或删除后重建) |
同上 |
注意事项/使用场景 列中的说明:
- 普通索引:适用于一般查询优化,提高查询速度。
- 唯一索引:保证字段值唯一性,常用于需要确保数据唯一性的场景。
- 主键索引:唯一且非空,用于标识表中的每一行,通常用于主键字段。
- 多列组合索引:适用于多个字段联合查询,需满足最左原则,即查询条件中的字段顺序要与创建索引时的字段顺序一致。
- 全文索引:适用于文本字段的模糊查询,如搜索文章、评论等文本内容。
删除方式 列中的说明:
- 对于普通索引、唯一索引和多列组合索引,可以使用
drop index
或alter table
语句来删除。 - 对于主键索引,只能使用
alter table
语句来删除。 - 若索引是在创建表时定义的,则无法直接删除索引,需要重建表或先删除表后重建。
查看方式 列中的说明:
- 可以使用
show create table
、show index
或show keys
语句来查看表的索引信息。这些语句会返回表的索引类型、索引名、字段名等详细信息。
问答环节
select查询语句执行速度慢:
原因:硬盘性能不足;别的应用导致服务器负载很高;mysql配置优化不够;表太大了;SQL语句语法复杂;索引失效
如果抛开其它原因,只做索引优化:先使用 explain 分析 select 语句(看 key、rows、tpye 字段),判断这个查询语句是否正确的使用了索引
再根据查询语句中 where 条件字段创建相应的单列索引或多列索引(多列组合索引要满足最左原则)
select语句避免在 where 条件字段使用 is null 判断,使用 != 或 <> 不等于判断,使用表达式或函数操作,使用 like查询以%开头