MySQL 之索引(简单版)

在这里插入图片描述

一、介绍

索引是一种数据结构,例如 B-Tree,它提高了从表中检索数据行的速度,但需要额外的写入和存储来维护它。

查询优化器可以使用索引来快速定位数据,而不必针对给定查询扫描表的每一行。

当您使用 主键唯一键创建表 时,MySQL 会自动创建一个名为 PRIMARY 的索引。该索引称为 聚集索引

PRIMARY 索引是特殊的,因为索引本身与数据一起存储在同一个表中。聚集索引强制执行表中行的顺序。

PRIMARY 索引以外的其他索引称为二级索引或非聚集索引。

二、MySQL 索引类型

默认情况下,如果您不指定索引类型,MySQL 将创建 B-Tree 索引。下面显示了基于表的存储引擎允许的索引类型:

存储引擎允许的索引类型
InnoDBBTREE
MyISAMBTREE
MEMORY/HEAPHASH,BTREE

在 InnoDB 中的索引种类?

物理存储上:聚簇索引、非聚簇索引(二级索引)

字段个数上:单列索引、联合索引

功能上:主键索引、唯一索引、普通索引、全文索引

三、创建索引

索引可以提高对表的数据检索速度。在 MySQL 数据库中,您可以使用 CREATE INDEX 语句向表提交索引。

对于一个具有大量数据行的表,如果你根据某个查询条件检索数据时很慢,可能是因为你没有在检索条件相关的列上创建索引。

索引类似于词典中的目录。如果您想要词典中查询一个词,正确的做法是先查看目录,再根据目录中的指示到指定的页面找到相关的词。正确的索引可以显著提高从数据库表中检索数据行的速度。

MySQL 允许您使用 CREATE INDEX 语句在指定的表上为指定的列创建索引。

1、CREATE INDEX 语法

您应该按照如下的语法使用 CREATE INDEX 为一个表添加一个索引:

CREATE [UNIQUE] INDEX index_name
[USING {BTREE | HASH}]
ON table_name (column_list)
[algorithm_option | lock_option];

说明:

  • UNIQUE 关键字表明此索引为 唯一索引。它是可选的。

  • index_name 是索引的名字。一个表中不应该出现两个相同名字的索引。

  • table_name 是表的名字。

  • column_list 是表中的列名。多个列名使用逗号分隔。

  • USING 子句指定索引的类型。可选值:BTREE,HASH。它是可选的。

  • algorithm_option 指定删除索引的算法。它使用以下的语法:

    ALGORITHM [=] {DEFAULT | INPLACE | COPY}
    

    ALGORITHM 子句是可选的。默认为 INSTANT。如果不支持 INSTANT,则使用 INPLACE

    使用 DEFAULT 和省略 ALGORITHM 子句效果相同。

    以下是对各个算法的说明:

    • COPY:对原表的副本进行操作,将原表中的表数据逐行复制到新表中。不允许并发 DML
    • INPLACE:操作避免复制表数据,但可能会就地重建表。在操作的准备和执行阶段,可能会短暂地对表进行独占元数据锁定。通常,支持并发 DML。
    • INSTANT:操作只修改数据字典中的元数据。在操作的执行阶段,可能会短暂地对表进行行独占元数据锁定。表数据不受影响,使操作瞬间完成。允许并发 DML。(在MySQL 8.0.12 中引入)
  • lock_option 指定删除索引的并发控制策略。它使用以下语法:

    LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}
    

    LOCK 子句是可选的。以下是对各个并发策略的说明:

    • DEFAULT

      给定 ALGORITHM 子句(如果有)和 ALTER TABLE 操作的最大并发级别:如果支持,则允许并发读取和写入。如果不是,则允许并发读取(如果支持)。如果不是,则强制执行独立访问。

    • NONE

      如果支持,允许并发读取和写入。否则,会发生错误。

    • SHARED

      如果支持,允许并发读取但阻止写入。即使存储引擎支持给定 ALGORITHM 子句(如果有)和 ALTER TABLE 操作的并发写入,写入也会阻止。如果不支持并发读取,则会发生错误。

    • EXCLUSIVE

      强制执行独占访问。即使存储引擎支持给定 ALGORITHM 子句(如果有)和 ALTER TABLE 操作的并发读/写,也会这样做。

在 MySQL 内部,CREATE INDEX 语句被映射为 ALTER TABLE … ADD INDEX … 语句。

2、CREATE INDEX 实例

在以下实例中,我们使用 Sakila 示例数据库 作为演示数据库 actor 表 进行演示。

以下语句查找名字为 NICK 的演员:

SELECT * FROM sakila.actor WHERE first_name = 'NICK';

这是输出:

+----------+------------+-----------+---------------------+
| actor_id | first_name | last_name | last_update         |
+----------+------------+-----------+---------------------+
|        2 | NICK       | WAHLBERG  | 2006-02-15 04:34:33 |
|       44 | NICK       | STALLONE  | 2006-02-15 04:34:33 |
|      166 | NICK       | DEGENERES | 2006-02-15 04:34:33 |
+----------+------------+-----------+---------------------+

您可以是使用 EXPLAIN 来查看以上 SELECT 语句的执行计划,以了解 MySQL 在内部如何执行此查询,如下所示:

EXPLAIN SELECT * FROM sakila.actor WHERE first_name = 'NICK';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | actor | NULL       | ALL  | NULL          | NULL | NULL    | NULL |  201 |    10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

如您所见,MySQL 必须扫描由 201 行组成的整个表才能找到具有符合条件的行。

现在,让我们使用以下 CREATE INDEX 语句为该列 first_name 创建索引:

CREATE INDEX first_name ON actor(first_name);

要查看索引是否创建成功,请使用以下 SHOW INDEXES 语句显示表 actor 的索引,例如:

SHOW INDEXES FROM actor;

这是输出:

+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name            | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| actor |          0 | PRIMARY             |            1 | actor_id    | A         |         201 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| actor |          1 | idx_actor_last_name |            1 | last_name   | A         |         122 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| actor |          1 | first_name          |            1 | first_name  | A         |         129 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+

然后,再次执行上面的 EXPLAIN 语句:

EXPLAIN SELECT * FROM sakila.actor WHERE first_name = 'NICK';

输出是:

+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key        | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | actor | NULL       | ref  | first_name    | first_name | 182     | const |    3 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+

如您所见,MySQL 只需从 first_name 指示的索引中定位其中的 3 行,而无需扫描整个表。

3、结论

在 MySQL 中,索引能提高从表中查询数据的效率。您可以使用 CREATE INDEX 为表创建索引。

四、删除索引

在MySQL 数据库中,您可以使用 DROP INDEX 从表中删除已有的索引。

有时候,您可能因为以下一些原因想要从一个表中删除一个或多个索引:

  • 创建了错误的索引
  • 为了更快,在插入或更新大量的数据之前先删除索引

MySQL 允许您使用 DROP INDEX 从表中删除已有的索引。

1、DROP INDEX 语法

您应该按照如下的语法使用 DROP INDEX 从一个表中删除一个索引:

DROP INDEX index_name
ON table_name
[algorithm_option | lock_option];

说明:

  • index_name 是索引的名字。

  • table_name 是表的名字。

  • algorithm_option 指定删除的索引算法。它使用以下的语法:

    ALGORITHM [=] {DEFAULT | INPLACE | COPY}
    

    ALGORITHM 子句是可选的。默认为 INPLACE。如果不支持 INPLACE,则使用 COPY

    使用 DEFAULT 和省略 ALGORITHM 子句效果相同。

    以下是对各个算法的说明:

    • COPY:对原表的副本进行操作,将原表中的表数据逐行复制到新表中。不允许并发 DML
    • INPLACE:操作避免复制表数据,但可能会就地重建表。在操作的准备和执行阶段,可能会短暂地对表进行独占元数据锁定。通常,支持并发 DML。
  • lock_option 指定删除索引的并发控制策略。它使用以下语法:

    LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}
    

    LOCK 子句是可选的。以下是对各个并发策略的说明。

    • DEFAULT

      给定 ALGORITHM 子句(如果有)和 ALTER TABLE 操作的最大并发级别:如果支持,则允许并发读取和写入。如果不是,则允许并发读取(如果支持)。如果不是,则强制执行独立访问。

    • NONE

      如果支持,允许并发读取和写入。否则,会发生错误。

    • SHARED

      如果支持,允许并发读取但阻止写入。即使存储引擎支持给定 ALGORITHM 子句(如果有)和 ALTER TABLE 操作的并发写入,写入也会阻止。如果不支持并发读取,则会发生错误。

    • EXCLUSIVE

      强制执行独占访问。即使存储引擎支持给定 ALGORITHM 子句(如果有)和 ALTER TABLE 操作的并发读/写,也会这样做。

在 MySQL 内部,DROP INDEX 语句被映射为 ALTER TABLE … DROP INDEX … 语句。

2、DROP INDEX 实例

在 MySQL 创建索引教程中,我们在我们在 Sakila 示例数据库中的 actor创建了一个索引 first_name

现在,我们将使用下面的语句将它删除:

DROP INDEX first_name ON actor;

要查看索引是否删除成功,请使用以下 SHOW INDEXES 语句显示表 actor 的索引,例如:

SHOW INDEXES FROM actor;

这是输出:

+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name            | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| actor |          0 | PRIMARY             |            1 | actor_id    | A         |         201 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| actor |          1 | idx_actor_last_name |            1 | last_name   | A         |         122 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+

3、删除主键索引

在 MySQL 中,主键的索引名字固定为 PRIMARY。要删除表 t 上的主键索引,请使用下面的语句:

DROP INDEX `PRIMARY` ON t;

4、结论

在 MySQL 中,您可以使用 DROP INDEX 为从表中删除指定的索引。

五、显示索引

在 MySQL 中,您可以使用 SHOW INDEXES 命令从表中查询索引信息。

1、SHOW INDEXES 语法

查询表索引信息,使用 SHOW INDEXES 如下语句:

SHOW INDEXES FROM db_name.table_name;

SHOW INDEXES FROM table_name IN db_name;

说明:

  • db_name 指示数据库的名字。如果您可以选择了数据库,则它可以省略。
  • table_name 指示表的名字。
  • 关键字 INDEXES 可以被替换为 INDEX 或者 KEYS
  • 关键字 IN 可以替换为 FROM
  • 关键字 FROM 可以替换为 IN

2、WHERE 子句

您可以在 SHOW INDEXES 语句中使用 WHERE 语句过滤结果。如下:

SHOW INDEXES FROM db_name.table_name WHERE condition;

3、SHOW INDEXES 返回的列

在这里插入图片描述

  • Table:表名
  • Non_unique:是否唯一索引。如果不是,则为 1,否则为 0。
  • Key_name:索引的名称。主键 索引的名称固定为 PRIMARY
  • Seq_in_index:索引中的序列号。第一列号从 1 开始。
  • Column_name:列名
  • Collation:排序规则表示列在索引中的排序方式。A 表示升序、B 表示降序或 NULL 表现未排序。
  • Cardinality:索引基数,它是索引中为唯一值的估计数量。注意,这个数字是不精确的,只是一个估计值。请注意,基础越高,查询优化器使用索引进行查找的机会就越大。
  • Sub_part:索引前缀。如果整个列都被索引,则为 NULL。否则,它会在列被部分索引的情况下显示索引字符数。
  • Packed:指示键是如何打包的;如果不是,则为 NULL
  • Null:如果该列可能包含 NULL 值为 YES,如果不包含则为空白。
  • Index_type:索引类型。可能的值:BTREE、HASH、RTREE 或 FULLTEXT
  • Comment:在其自己的列中描述的有关索引的信息。
  • Index_comment:显示创建索引时使用 COMMENT 属性指定的索引的注释。
  • Visible:索引对查询优化器是否可见或不可见;如果可见为 YES,否则为 NO
  • Expression:如果索引使用表达式而不是列或列前缀值时有值。此时 column_name 列为 NULL。

4、SHOW INDEXES 实例

在以下实例中,我们使用 Sakila 示例数据库中的 film进行演示。

①显示全部索引

要显示 film 表中的所有的索引,请使用以下语句:

SHOW INDEXES FROM sakila.film;
+-------+------------+-----------------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name                    | Seq_in_index | Column_name          | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+-----------------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| film  |          0 | PRIMARY                     |            1 | film_id              | A         |        1000 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| film  |          1 | idx_title                   |            1 | title                | A         |        1000 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| film  |          1 | idx_fk_language_id          |            1 | language_id          | A         |           1 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| film  |          1 | idx_fk_original_language_id |            1 | original_language_id | A         |           1 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+-------+------------+-----------------------------+--------------+----------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+

②过滤索引

您可以使用 WHERE 子句对 SHOW INDEXES 的结果进行过滤。比如,如果您想要从 film 表中获取所有的唯一索引,请使用以下语句:

SHOW INDEXES FROM sakila.film WHERE Non_unique = 0;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| film  |          0 | PRIMARY  |            1 | film_id     | A         |        1000 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+

5、结论

在 MySQL 中,索引能提高从表中查询数据的效率。您可以使用 SHOW INDEXES 语句获取一个表的索引以了解该表中的索引情况。您还可以使用 WHERE 子句对 SHOW INDEXES 结果进行过滤。

  • 10
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亿先生@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值