【MySQL数据库】MySQL索引

MySQL索引

索引是一种数据结构,用于快速查找数据库表中的记录。在MySQL中,索引类似于书的目录,通过索引可以快速定位到表中的某一行数据,而不需要扫描整个表。索引存储了索引列的值以及这些值对应的行的物理地址(或称为行指针)。

  • 排序的列表:索引是一个按索引列排序的列表。
  • 物理地址:索引条目中包含了索引列的值和包含该值的行的物理地址。
  • 加速查询:使用索引可以加速查询操作,因为数据库系统可以利用索引快速定位到所需的数据行。

索引的概念

  1. 定义:索引是一个排序后的列表,其中存储了索引值以及这些值对应数据行的物理地址。
  2. 作用:通过索引,数据库可以快速定位到所需数据行,避免全表扫描,从而加速查询。
  3. 类比:索引类似于书籍的目录,通过目录中的页码可以迅速找到内容。
  4. 排序方式:索引是基于表中一列或多列的值进行排序的。
  5. 目的:创建索引主要是为了加快数据查找和排序速度。

索引的作用

  1. 加速查询:合适的索引能显著提高数据库查询速度。
  2. 大数据量优势:在处理大型表或多表查询时,索引的效果尤为明显。
  3. 降低成本:减少IO操作和排序成本。
  4. 数据唯一性:通过唯一性索引确保数据的唯一性。
  5. 连接加速:加快表与表之间的连接操作。
  6. 分组排序优化:在执行GROUP BY和ORDER BY操作时提高效率。
  7. 数据恢复性能:在搜索和恢复数据时提升性能。

索引的副作用

尽管索引带来了诸多好处,但也有一些潜在的副作用需要注意:

  1. 空间消耗:索引占用额外的磁盘空间。
    • MyISAM:索引文件与数据文件分离。
    • InnoDB:数据文件本身就是索引文件(聚集索引)。
  2. 更新开销:更新包含索引的表比更新无索引的表更耗时,因为需要同时更新索引。
  3. 选择不当的索引:如果索引选择不当,可能会导致查询性能下降,甚至不如没有索引的情况。

创建索引的原则依据

创建索引时,需要遵循一些原则以确保索引的有效性:

  • 主键和外键:主键和外键列通常应该建立索引,因为它们经常用于查询和连接操作。
  • 记录数超过300行的表:对于包含大量记录的表,应该考虑建立索引以加速查询。
  • 连接字段:在经常用于连接(JOIN)操作的字段上建立索引。
  • 唯一性差的字段:唯一性差的字段(如性别、布尔值等)不适合建立索引,因为索引的选择性较差。
  • 更新频繁的字段:更新频繁的字段不适合建立索引,因为索引的更新开销较大。
  • WHERE子句中的字段:经常出现在WHERE子句中的字段,特别是大表的字段,应该建立索引。
  • GROUP BY和ORDER BY字段:在经常进行GROUP BY和ORDER BY操作的字段上建立索引。
  • 选择性高的字段:索引应该建在选择性高的字段上,即不同值较多的字段。
  • 小字段:索引应该建在小字段上,因为大字段(如长文本)的索引开销较大。

示例

假设我们有一个名为employees的表,包含以下字段:id(主键)、name(姓名)、age(年龄)、department(部门)和salary(薪水)。以下是一些可能的索引策略:

  • 主键索引:在id字段上创建主键索引(通常是自动创建的)。
  • 唯一索引:如果email字段是唯一的,可以在email字段上创建唯一索引。
  • 组合索引:在经常一起查询的字段上创建组合索引,如(department, age)
  • 全文索引:如果需要在namedescription等文本字段上进行全文搜索,可以创建全文索引。

创建索引的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 索引分类与创建

索引分类

  1. 普通索引
    • 最基本的索引类型,没有唯一性限制,允许有空值。
    • 创建方式:
      • 直接创建:CREATE INDEX 索引名 ON 表名 (列名[(length)]);
      • 修改表结构:ALTER TABLE 表名 ADD INDEX 索引名 (列名);
      • 创建表时指定:CREATE TABLE 表名 (字段1 数据类型, ..., INDEX 索引名 (列名));
  2. 唯一索引
    • 与普通索引类似,但要求索引列的值必须唯一。
    • 允许有空值,但空值不参与唯一性比较。
    • 创建方式:
      • 直接创建:CREATE UNIQUE INDEX 索引名 ON 表名(列名);
      • 修改表结构:ALTER TABLE 表名 ADD UNIQUE 索引名 (列名);
      • 创建表时指定:CREATE TABLE 表名 (字段1 数据类型, ..., UNIQUE 索引名 (列名));
  3. 主键索引
    • 特殊的唯一索引,必须指定为“PRIMARY KEY”。
    • 一个表只能有一个主键索引,不允许有空值。
    • 创建方式:
      • 创建表时指定:CREATE TABLE 表名 ([...], PRIMARY KEY (列名));
      • 修改表结构:ALTER TABLE 表名 ADD PRIMARY KEY (列名);
  4. 组合索引(多列索引)
    • 在多列上创建的索引,查询时满足最左前缀原则。
    • 创建方式:CREATE INDEX 索引名 ON 表名 (列名1, 列名2, ...);
  5. 全文索引(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 BYGROUP 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 indexalter table 语句来删除。
  • 对于主键索引,只能使用 alter table 语句来删除。
  • 若索引是在创建表时定义的,则无法直接删除索引,需要重建表或先删除表后重建。

查看方式 列中的说明:

  • 可以使用 show create tableshow indexshow keys 语句来查看表的索引信息。这些语句会返回表的索引类型、索引名、字段名等详细信息。

问答环节

select查询语句执行速度慢:
原因:硬盘性能不足;别的应用导致服务器负载很高;mysql配置优化不够;表太大了;SQL语句语法复杂;索引失效
如果抛开其它原因,只做索引优化:先使用 explain 分析 select 语句(看 key、rows、tpye 字段),判断这个查询语句是否正确的使用了索引
再根据查询语句中 where 条件字段创建相应的单列索引或多列索引(多列组合索引要满足最左原则)
select语句避免在 where 条件字段使用 is null 判断,使用 != 或 <> 不等于判断,使用表达式或函数操作,使用 like查询以%开头

猜你喜欢

转载自blog.csdn.net/Karoku/article/details/142882580