第8章 索引index

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 第8章 索引index

第8章 索引index

索引是在数据库表的字段上添加的,是为了提高查询效率存在的一种机制。

一张表的一个字段可以添加一个索引,当然,多个字段联合起来也可以添加索引。

索引相当于一本书的目录,是为了缩小扫描范围而存在的一种机制。

对于一本字典来说,查找某个汉字有两种方式:

第一种方式:一页一页挨着找,直到找到为止;即全字典扫描,效率低

第二种方式:先通过目录(索引)去定位一个大概的位置,然后直接定位到这个

位置,做局域性扫描,缩小扫描的范围,快速查找

t_user

id(idIndex)   name(nameIndex)   email(emailIndex)   address  (emailAddressIndex)
----------------------------------------------------------------------------------
  1       zhangsan...
  2       lisi
  3       wangwu
  4       zhaoliu
  5       hanmeimei
  6       jack
select * from t_user where name='jack';

以上的这条SQL语句会去name字段上扫描,因为查询条件是:name=‘jack’

如果name字段上没有添加索引(目录),或者说没有给name字段创建索引,MySQL会进行全扫描,会将name字段上的每一个值都比对一遍。效率比较低。

8.1 查询两种方式

  1. 全表扫描
  2. 根据索引检索

注意:

在实际中,汉语字典前面的目录是排序的,按照a b c d e f…排序,

为什么排序呢?因为只有排序了才会有区间查找这一说!(缩小扫描范围其实就是扫描某个区间罢了!)

在mysql数据库当中索引也是需要排序的,并且这个索引的排序和TreeSet

数据结构相同。TreeSet(TreeMap)底层是一个自平衡的二叉树!在mysql当中索引是一个B-Tree数据结构。

遵循左小右大原则存放。采用中序遍历方式遍历取数据。

8.2 索引的实现原理

假设有一张用户表:t_user

id(PK)          name            每一行记录在硬盘上都有物理存储编号
----------------------------------------------------------------------------------
100           zhangsan            0x1111
120           lisi              0x2222
99            wangwu              0x8888
88            zhaoliu             0x9999
101           jack              0x6666
55            lucy              0x5555
130           tom               0x7777

提醒1:任何数据库中主键上都会自动创建索引,所以id字段上自动有索引。 另外,一个字段如果有unique约束,也会自动创建索引。

提醒2:在任何数据库当中,任何一张表的任何一条记录在硬盘存储上都有一个硬盘的物理存储编号

提醒3:在mysql当中,索引是一个单独的对象,不同的存储引擎以不同的形式存在,

在MyISAM存储引擎中,索引存储在一个.MYI文件中;

在InnoDB存储引擎中索引存储在一个逻辑名称叫做tablespace的当中;

在MEMORY存储引擎当中索引被存储在内存当中。

不管索引存储在哪里,索引在mysql当中都是一个树的形式存在。(自平衡二叉树:B-Tree)

什么时候考虑给字段添加索引?

  • 数据量庞大
  • 该字段经常出现在where的后面,以条件的形式存在;就是说该字段频繁被扫描
  • 该字段很少的DML(insert delete update)操作;就是说增删改少

8.3 索引的创建、删除

创建索引:create index emp_ename_index on emp(ename);

例:给emp表的ename字段添加索引,起名:emp_ename_index

mysql> create index emp_ename_index on emp(ename);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

删除索引:drop index emp_ename_index on emp;

mysql> drop index emp_ename_index on emp;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

8.4 查看是否使用索引检索:explain

mysql> explain select * from emp where ename='KING';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | emp   | ALL  | NULL          | NULL | NULL    | NULL |   14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

扫描14条记录:说明没有使用索引。type=ALL

例:建立索引扫描:

mysql> create index emp_ename_index on emp(ename);
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> explain select * from emp where ename='KING';
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys   | key             | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------------+
|  1 | SIMPLE      | emp   | ref  | emp_ename_index | emp_ename_index | 33      | const |    1 | Using where |
+----+-------------+-------+------+-----------------+-----------------+---------+-------+------+-------------+
1 row in set (0.01 sec)

8.5 索引失效情况

第1种:模糊匹配%开头情况

mysql> select * from emp where ename like '%T';
+-------+-------+---------+------+------------+---------+------+--------+
| EMPNO | ENAME | JOB     | MGR  | HIREDATE   | SAL     | COMM | DEPTNO |
+-------+-------+---------+------+------------+---------+------+--------+
|  7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL |     20 |
+-------+-------+---------+------+------------+---------+------+--------+
1 row in set (0.00 sec)
mysql> explain select * from emp where ename like '%T';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | emp   | ALL  | NULL          | NULL | NULL    | NULL |   14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

原因:模糊匹配以“%”开头了!

第2种:使用or情况

or两边的条件字段都要有索引,才会走索引;

mysql>  explain select * from emp where ename = 'KING' or job = 'MANAGER';   //job字段没有建立索引
+----+-------------+-------+------+-----------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys   | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+-----------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | emp   | ALL  | emp_ename_index | NULL | NULL    | NULL |   14 | Using where |
+----+-------------+-------+------+-----------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

第3种:符合索引情况:

复合索引:两个字段,或者更多的字段联合起来添加一个索引。

使用复合索引时,若没有使用左侧的列查找,索引失效。最左原则

mysql> create index emp_job_sal_index on emp(job,sal);    //建立复合索引   左边字段是job
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> explain select * from emp where job='MANAGER';  //最左原则  左边行
+----+-------------+-------+------+-------------------+-------------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys     | key               | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+-------------------+-------------------+---------+-------+------+-------------+
|  1 | SIMPLE      | emp   | ref  | emp_job_sal_index | emp_job_sal_index | 30      | const |    3 | Using where |
+----+-------------+-------+------+-------------------+-------------------+---------+-------+------+-------------+
1 row in set (0.00 sec)
mysql> explain select * from emp where sal=800;        //右边不行
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | emp   | ALL  | NULL          | NULL | NULL    | NULL |   14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.01 sec)

第4种:where当中索引列参加运算的情况:

mysql> create index emp_sal_index on emp(sal);     //建立索引
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> explain select * from emp where sal=800;   //正常情况没问题
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key           | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
|  1 | SIMPLE      | emp   | ref  | emp_sal_index | emp_sal_index | 9       | const |    1 | Using where |
+----+-------------+-------+------+---------------+---------------+---------+-------+------+-------------+
1 row in set (0.00 sec)
mysql> explain select * from emp where sal+1 = 800;   //参加运算索引失效
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | emp   | ALL  | NULL          | NULL | NULL    | NULL |   14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.01 sec)

第5种:where当中索引列使用了函数的情况:

mysql> explain select * from emp where lower(ename) = 'smith';
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | emp   | ALL  | NULL          | NULL | NULL    | NULL |   14 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)

8.6 索引分类

  1. 单一索引:一个字段上添加索引
  2. 复合索引:两个字段或者更多的字段上添加索引
  3. 主键索引:主键上添加索引
  4. 唯一性索引:具有unique约束的字段上添加索引

    注意:唯一性比较弱的字段上添加索引用处不大。
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
7月前
|
存储 算法 关系型数据库
十五、索引 (Index)
十五、索引 (Index)
78 0
|
7月前
|
索引
根据索引值计算item所在行列(row,col)索引序号(index)
根据索引值计算item所在行列(row,col)索引序号(index)
|
存储 缓存 索引
PG13 B-tree索引去重
PG13 B-tree索引去重
96 0
|
存储 数据库 索引
解析B+Tree索引在H2中的实现
提到数据库索引的时候,一般都会提到 B+Tree,因为主流数据库都使用它。我们的DawnSql使用的是 H2 中的存储引擎,因此也是使用 B+Tree。这篇文章的目的是帮助读者更快的掌握 B+Tree 在存储引擎中的作用,以及具体的实现。
解析B+Tree索引在H2中的实现
|
SQL 存储 关系型数据库
为什么我建议在复杂但是性能关键的表上所有查询都加上 force index
为什么我建议在复杂但是性能关键的表上所有查询都加上 force index
为什么我建议在复杂但是性能关键的表上所有查询都加上 force index
|
关系型数据库 MySQL 索引
覆盖索引 cover index
覆盖索引 cover index MySQL InnoDB
166 0
|
Web App开发 JavaScript
深入理解z-index
要解决的问题 在页面编写的过程中,经常需要处理元素的重叠。重叠的顺序不当则容易造成元素被错误地遮盖等现象。一般地,有很多人认为只需要指定元素的z-index即可调整重叠的顺序,但是实际上并不是这样的。
1550 0
|
关系型数据库 索引 存储
覆盖索引 covering index
覆盖索引定义 应用场景 测试
2548 0