MySQL系列索引专题

news2024/12/29 8:38:41

存储引擎

1.MySQL 的体系结构可以分为四层

在这里插入图片描述

  • 连接层:最上层是一些客户端和链接服务,主要完成一些类似于连接处理、授权认证、及相关的安全方案。服务器也会为安全接入的每个客户端验证它所具有的操作权限
  • 服务层:第二层架构主要完成大多数的核心服务功能,如 SQL 接口,并完成缓存的查询,SQL 的分析和优化,部分内置函数的执行。所有跨存储的引擎的功能也在这一层实现,如 过程、函数等
  • 引擎层:存储引擎真正的负责了 MySQL 中数据的存储和提取,服务器通过 API 和存储引擎进行通信。
  • 存储层:数据存储层,主要将数据(如:redolog、undolog、数据、索引、二进制日志、错误日志、查询日志、慢查询日志等)存储在文件系统之上,并完成与存储引擎的交互。

点击此处即可领取282G网络安全学习资源

2.介绍存储引擎

  • 属于表的存储引擎,就是存储引擎是在创建表的时候指定的,通过 show create table 表名 可以查看

在这里插入图片描述

  • 通过 show engines 可以查看当前数据库支持的引擎
engine 引擎名
support 是否支持
comment 描述
transactions 是否支持事务
XA 是否支持分布式事务处理规范 [就是事务相关的一种规范]
Savepoints 是否支持保存点[用于取消部分事务,结束事务时,会自动删除该事务中所定义的所有保存点]

在这里插入图片描述

  • 我们可以在创建表的时候指定存储引擎 engine = 存储引擎名
 create table my_myisam{
	id int,
	username varchar(10),
} engine = MyISAM;

3.存储引擎的特点

InnoDB 存储引擎:
是一种兼顾高可靠性和高性能的通用存储引擎,在 MySQL 5.5 之后, InnoDB 是默认的 MySQL 存储引擎

  • DML 操作遵循 ACID 模型,支持事务
  • 行级锁,提高并发访问性能
  • 支持外键 Foreign Key 约束,保证数据的完整性和正确性

(1)表空间文件

  • nnoDB 引擎的每张表都会对应一个 xxx.idb 这样的表空间文件,存储表结构、数据和索引
早期表结构 xxx.frm,在 MySQL8 中采用 xxx.sdi 的形式
  • 通过 innodb_file_per_table 参数可以指定是一张表对应一个表空间文件,还是多张表对应一个表空间文件
默认是一张表对应一个表空间文件 [Value = ON]

通过 show variables like 'innodb_file_per_table' 指令可以查看配置情况

在这里插入图片描述

  • 我们可以打开 MySQL 数据存放目录 C:\ProgramData\MySQL\MySQL Server 8.0\Data\zwh 查看表空间文件
    在这里插入图片描述
  • 在 Dos 中使用 idb2sdi 指令可以从 idb 文件中提取 sdi(表结构)信息
    (2)逻辑存储空间
    在这里插入图片描述
  • 表空间:用来存储索引空间和数据空间,是逻辑存储结构的最高层次,对应 xxx.idb 文件
  • 段:表空间由多个段组成,例如:数据段、索引段、回滚段等,由引擎自己完成段的管理
  • 区:一个段又包含多个区,区是表空间的单元结构,每个区的大小为 1M
  • 页:也是组成区的最小单元,大小为 16KB,所以一个区中有64个连续的页,页也是 InnoDB 存储引擎磁盘管理的最小单元,为了保证页的连续性, InnoDB 存储引擎每次从磁盘申请 4-5 个区
  • 行:InnoDB 存储引擎是面向行的,也就是说数据按照行进行存放的,每一行除了定义表时所指定的字段以外,还包含两个隐藏字段 【事务id、滚动指针】

MyISAM 存储引擎:

  • 是 MySQL 早期默认的存储引擎
 不支持事务和外键

支持表锁,但不支持行锁

访问速度快
  • 文件格式
 xxx.sdi 存储表结构信息
xxx.MYD 存储数据信息
xxx.MYI 存储索引

在这里插入图片描述
Memory 存储引擎

  • 表数据是存储在内存中的,所以这些表只能作为临时表或缓存使用

内存存放、hash 索引(默认)

  • 文件格式

xxx.sdi 存储表结构信息
在这里插入图片描述
4.这三种引擎都有什么区别呢?
在这里插入图片描述
如何选择存储引擎呢?

  • 根据应用系统的特点选择合适的存储引擎,复杂的应用系统还可以选择多种存储引擎组合使用

  • InnoDB 应用场景:
    应用对事务的完整性有较高的要求,并发条件下要求数据的一致性
    数据除了插入和查询外还有很多的更新、删除操作

  • MyISAM 应用场景:
    以插入和查询操作为主,很少删除和更新操作,对事务完成性、并发要求不高

  • Memory 应用场景:
    将数据保存到内存中,访问速度快,用于临时表和缓存功能的实现
    对表的大小有限制,而且无法保证数据的安全性
    在这里插入图片描述

索引

索引概述

  • 索引是帮助 MySQL 高效获取数据的数据结构(有序)

  • 正常我们要查询一条语句可能要扫描全表,使用索引可能遍历几个数
    就可以获得结果,接下来通过案例简单说明:

假设我们要查询表中年龄为 45 的所有用户信息: select * from user where age = 45
在无索引情况下,就需要从第一行开始扫描,一直扫描到最后一行,我们称之为 全表扫描,性能很低
如果我们针对于这张表建立了索引,假设索引结构就是二叉树,那么也就意味着,会对age这个字段建 立一个二叉树的索引结构 【原理介绍示意图,并非索引真实数据结构】

在这里插入图片描述

因为这是一颗排序二叉树,所以我们只需要遍历三个数据就可以获得结果,极大的提高了查询效率

  • 那么索引就没有缺点吗?
    索引 虽然可以提高数据检索的效率,降低数据库 IO 成本,但是索引也要占用一定的数据空间
    索引列对数据进行排序,降低数据排序成本、降低 CPU 的消耗,提高查询效率的同时,降低了表的更新速度

索引结构

1.内容概述
MySQL 的索引是子啊存储引擎层实现的,不同的存储引擎有不同的索引结构,主要包含以下几种:
在这里插入图片描述
这几种是 MySQL 数据库所支持的所有的索引结构,下面是不同存储引擎对这几种索引的支持情况
在这里插入图片描述
2.二叉树
如果选择二叉树作为索引结构,会存在以下缺点:

  • 顺序插入时,会形成一个链表,查询性能较低
    在这里插入图片描述
  • 大数据量情况下,层级较深,检索速度较慢
    如果想避免出现二叉树很高的情况,我们当然可以选择红黑树,因为红黑树是一颗自平衡二叉树

在这里插入图片描述
但是大数据量情况下,还会产生较深的层级,检索速度还是很慢
3.B树
B-Tree (B树)是一种多叉路平衡查找树,相对于二叉树,B树每个节点可以有多个分支,我们称之为多叉

  • 以一颗最大度数(max-degree) 为5的b树为例,那么这个 B树 每个结点最多可以存储 4个key,5个指针 【度数就是结点个数】
    在这里插入图片描述

  • 一旦结点存储的 key 数量达到5,就会裂变,中间元素向上分裂

  • 在 B 树中,非叶子结点和叶子结点都会存放数据
    4.B+ 树
    在这里插入图片描述

  • B+树是B树的变种,我们可以看到
    绿色的部分是索引部分,只具有索引作用,不存储任何数据
    红色的部分是数据存储部分,在其叶子结点中存储具体的数据

  • B+树相对于B树有以下几个区别:
    所有的数据都会存储到叶子结点上
    叶子结点形成一个单向链表
    非叶子结点仅仅起到索引数据作用

上面介绍的是标准的 B+ 树结构,MySQL对其进行了优化,增加了指向相邻叶子结点的链表指针,提高了区间访问的性能,有利于排序
在这里插入图片描述
5.Hash
哈希索引采用 hash 算法,将键值换成新的 hash 值,映射到对应的槽位上,然后存储在 hash 表中

如果多个键值映射到了同一个槽位,那么就用链表来解决 hash 冲突

在这里插入图片描述
hash 索引有以下特点:

  • 只能用于对等比较 (in, =) 不能用于范围查询 (> < >= <=, …)
  • 无法利用索引完成排序操作
  • 查询效率较高,不出现哈希冲突的情况下只需要检索一次,效率远远超过 B+ 树
  • 在 MySQL 中 Memory 存储引擎支持 Hash索引,因为 InnoDB 有自适应 hash 功能,所以 InnoDB 存储引擎也能用哈希索引

为什么 InnoDB 存储引擎选择 B+树索引结构?

  • 相对于二叉树,层级更少,搜索效率高
  • B-tree 无论叶子结点还是非叶子结点都会保存数据,因为页的大小是固定的,所以一页存储的键值、指针减少,和 B+tree 保存同样的数据树的高度更高,所以性能不如 B+树好
  • 相对于 hahs 索引,B+tree 支持范围匹配和排序操作

索引分类
在 MySQL 数据库中,将索引分为以下几类:主键索引、唯一索引、常规索引、全文索引

在这里插入图片描述
而在 InnoDB 存储引擎中,根据索引的存储形式,又分为以下两种:
在这里插入图片描述

聚集索引选取规则:

  • 如果存在主键,主键索引就是聚集索引
  • 如果不存在主键,将使用第一个唯一索引作为聚集索引
  • 如果表没有主见,也没有合适的唯一索引,则 InnoDB 会自动生成一个 rowid 作为隐藏的聚集索引

我们来看一下聚集索引和二级索引的具体结构:
在这里插入图片描述

  • 聚集索引的叶子结点下挂的是这一行的数据
  • 二级索引的叶子节点下挂的是该字段的主键值
    我们来分析一下执行SQL语句时查找流程:select * from user where name = ‘Arm’
    在这里插入图片描述

第一步,根据 name 字段进行查询,所以先根据 name = ‘Arm’ 到 name 字段的二级索引中进行匹配查找,但是二级索引中只能查找到 Arm 对应的主键值 10
第二步,因为我们要获得的是 Arm 的全部信息,所以根据主键值10,到聚集索引中查找,最终找到10对应的行 row
第三步,返回这一行的数据

此处采用的是回表查询:先到二级索引中查找数据,找到主键值,然后再到聚合索引中根据主键值,获取数据

我们来看两道题思考一下:

以下两条 SQL 语句,哪个执

// 将 id 设为主键,name 设置了二级索引
A. select * from user where id = 10;
B. select * from user where name = 'Arm';

答:A 选项的执行效率更高,因为 A 选项的语句直接走的聚集索引,然而B选项要先走二级索引,然后再走聚集索引,也就是我们常说的回表查询

InnoDB 主键索引的 B+树高度为多高呢?

在这里插入图片描述
假设:一行数据大小为 1k, 一页中可以存储 16 行, InnoDB 的指针占用 6 个字节的空间,主键最多占用 8 个字节 (bigint)
(1) 如果高度为 2,假设页中有n个key,那么就有 n + 1 个指针
n * 8 + (n - 1) * 6 = 16 * 1024, 解得 n 约为 1170
1171 * 16 = 18736 // 1171 个指针对应 1171 个子节点(页),1页存储16行
所以 如果树的高度为2,则可以存储 18000 多条记录
(2) 如果高度为 3
1171 * 1171 * 16 = 21939856 // 一层1171个指针,两层两个 1171 相乘,最后乘一个指针对应页的记录条数
所以 如果树的高度为3,则可以存储 2200w 左右的记录

索引语法

在 MySQL 中与索引相关的基础语法:

  • 创建索引 create [unique | fulltext] index index_name on table_name (index_col_name, …)
  • 查看索引 show index from table_name
  • 删除索引 drop index index_name on table_name

单纯看命令有可能看不懂或记不住,所以通过案例来进行演示
1.准备数据

create table tb_user(
id int primary key auto_increment comment ‘主键’,
name varchar(50) not null comment ‘用户名’,
phone varchar(11) not null comment ‘手机号’,
email varchar(100) comment ‘邮箱’,
profession varchar(11) comment ‘专业’,
age tinyint unsigned comment ‘年龄’,
gender char(1) comment ‘性别 , 1: 男, 2: 女’,
status char(1) comment ‘状态’,
createtime datetime comment ‘创建时间’
) comment ‘系统用户表’;
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘吕布’, ‘17799990000’, ‘lvbu666@163.com’, ‘软件工程’, 23, ‘1’,
‘6’, ‘2001-02-02 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘曹操’, ‘17799990001’, ‘caocao666@qq.com’, ‘通讯工程’, 33,
‘1’, ‘0’, ‘2001-03-05 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘赵云’, ‘17799990002’, ‘17799990@139.com’, ‘英语’, 34, ‘1’,
‘2’, ‘2002-03-02 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘孙悟空’, ‘17799990003’, ‘17799990@sina.com’, ‘工程造价’, 54,
‘1’, ‘0’, ‘2001-07-02 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘花木兰’, ‘17799990004’, ‘19980729@sina.com’, ‘软件工程’, 23,
‘2’, ‘1’, ‘2001-04-22 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘大乔’, ‘17799990005’, ‘daqiao666@sina.com’, ‘舞蹈’, 22, ‘2’,
‘0’, ‘2001-02-07 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘露娜’, ‘17799990006’, ‘luna_love@sina.com’, ‘应用数学’, 24,
‘2’, ‘0’, ‘2001-02-08 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘程咬金’, ‘17799990007’, ‘chengyaojin@163.com’, ‘化工’, 38,
‘1’, ‘5’, ‘2001-05-23 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘项羽’, ‘17799990008’, ‘xiaoyu666@qq.com’, ‘金属材料’, 43,
‘1’, ‘0’, ‘2001-09-18 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘白起’, ‘17799990009’, ‘baiqi666@sina.com’, ‘机械工程及其自动
化’, 27, ‘1’, ‘2’, ‘2001-08-16 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘韩信’, ‘17799990010’, ‘hanxin520@163.com’, ‘无机非金属材料工
程’, 27, ‘1’, ‘0’, ‘2001-06-12 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘荆轲’, ‘17799990011’, ‘jingke123@163.com’, ‘会计’, 29, ‘1’,
‘0’, ‘2001-05-11 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘兰陵王’, ‘17799990012’, ‘lanlinwang666@126.com’, ‘工程造价’,
44, ‘1’, ‘1’, ‘2001-04-09 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘狂铁’, ‘17799990013’, ‘kuangtie@sina.com’, ‘应用数学’, 43,
‘1’, ‘2’, ‘2001-04-10 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘貂蝉’, ‘17799990014’, ‘84958948374@qq.com’, ‘软件工程’, 40,
‘2’, ‘3’, ‘2001-02-12 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘妲己’, ‘17799990015’, ‘2783238293@qq.com’, ‘软件工程’, 31,
‘2’, ‘0’, ‘2001-01-30 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘芈月’, ‘17799990016’, ‘xiaomin2001@sina.com’, ‘工业经济’, 35,
‘2’, ‘0’, ‘2000-05-03 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘嬴政’, ‘17799990017’, ‘8839434342@qq.com’, ‘化工’, 38, ‘1’,
‘1’, ‘2001-08-08 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘狄仁杰’, ‘17799990018’, ‘jujiamlm8166@163.com’, ‘国际贸易’,
30, ‘1’, ‘0’, ‘2007-03-12 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘安琪拉’, ‘17799990019’, ‘jdodm1h@126.com’, ‘城市规划’, 51,
‘2’, ‘0’, ‘2001-08-15 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘典韦’, ‘17799990020’, ‘ycaunanjian@163.com’, ‘城市规划’, 52,
‘1’, ‘2’, ‘2000-04-12 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘廉颇’, ‘17799990021’, ‘lianpo321@126.com’, ‘土木工程’, 19,
‘1’, ‘3’, ‘2002-07-18 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘后羿’, ‘17799990022’, ‘altycj2000@139.com’, ‘城市园林’, 20,
‘1’, ‘0’, ‘2002-03-10 00:00:00’);
INSERT INTO tb_user (name, phone, email, profession, age, gender, status,
createtime) VALUES (‘姜子牙’, ‘17799990023’, ‘37483844@qq.com’, ‘工程造价’, 29,
‘1’, ‘4’, ‘2003-05-26 00:00:00’);

在这里插入图片描述

– A. name字段为姓名字段,该字段的值可能会重复,为该字段创建索引。
create unique index name_index on tb_user (name);
show index from tb_user;
– B. phone手机号字段的值,是非空,且唯一的,为该字段创建唯一索引。
create unique index phone_index on tb_user (phone);
– C. 为profession、age、status创建联合索引。
create index pas on tb_user (profession, age, status);
– D. 为email建立合适的索引来提升查询效率。
create unique index email_index on tb_user (email);
– 查看所有索引
show index from tb_user;

在这里插入图片描述
SQL性能分析
1.SQL 执行频率分析
在 MySQL 客户端连接成功后,通过 show [session | global] status 命令可以提供服务器状态信息

mysql复制代码-- 插入次数
show global status like ‘Com_insert’;
– 删除次数
show global status like ‘Com_delete’;
– 查询次数
show global status like ‘Com_select’;
– 更新次数
show global status like ‘Com_update’;

主要的作用就是可以让我们知道当前数据库是以查询为主还是增删改为主,从而为数据库优化提供参考依据,要是以查询为主就要对数据库索引进行优化了
2.慢查询日志
我们可以借助慢查询日志去定义对哪些查询语句进行优化,慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认 10 秒)的所有 SQL语句的日志
mysql复制代码–

我使用的是 Linux 中 Docker 运行的 MySQL8 容器
– 进入容器内部 >> 进入 MySQL >> 查看慢查询相关内容
show variables like ‘slow%’;

在这里插入图片描述

– 如果没有开启慢查询,可以通过下面的指令开启
set global slow_query_log = ON;
– 设置慢 sql 阈值time,超过阈值就会被记录为慢 sql
set global slow_launch_time = time;

– 因为我不知道我的mysql容器数据卷,让我挂载到哪里去了
docker inspect mysql8
– 找到 Mounts 部分,上面是Linux中的目录,下面的MySQL容器中的目录
“/mydata/mysql/conf”
“/etc/mysql/conf.d”
“/mydata/mysql/data”
“/var/lib/mysql”
“/mydata/mysql/log”
“/logs”
– 根据上图的 slow_query_log_file 我找到了我慢查询文件位置
/mydata/mysql/data/cea8370ff66d-slow.log

– 为了模拟慢查询,我创建了一个表
create table test(
id int,
name varchar(10)
);
– 网上搜了一段通过存储过程模拟循环插入大量数据
CREATE PROCEDURE insert_data(IN start INT, IN end INT)
BEGIN
DECLARE i INT DEFAULT start;
WHILE i <= end DO
INSERT INTO test
VALUES (i, “test_datas”);
SET i = i + 1;
END WHILE;
END $$
DELIMITER ;
– 执行下面这个方法开始插入数据,本来想插入 100w 条数据,实在太慢了就插入了 15w 条
CALL insert_data(1, 10000000);
– 执行查询,没让我失望还是达到了慢查询的标准
select * from test;

在这里插入图片描述

– 然后我们去 Linux 服务器中查看一下慢查询日志
tail -f /mydata/mysql/data/cea8370ff66d-slow.log

在这里插入图片描述
通过慢查询日志,就可以定位到执行效率较低的 SQL,从而有针对性的进行优化
3.profile 详情
show profiles 能够帮助我们看到 SQL 语句时间主要消耗在哪块,有助于我们进行 SQL 优化

可以看到当前 MySQK 是否支持 profile 操作 [1 YES(开启) 0 NO(关闭)]
select @@have_profiling;
– @@profiling 用于控制查询分析的详细程度
– 值为0代表不会记录任何信息、值为1代表仅记录主要查询的信息、值为2还会记录所有子查询的信息
set profiling = 1;

在这里插入图片描述
接下来通过案例介绍 profiles 的用法

select * from tb_user;
select * from tb_user where id = 1;
select * from tb_user where name = ‘白起’;
select count(*) from tb_user;
– 查看每一条 SQL 的耗时情况
show profiles;
– 查看指定 query_id 的 SQL 语句各个阶段执行耗时情况
show profile for query 94;
– 查看指定 query_id 的 SQL 语句 CPU 的使用情况
show profile cpu for query 94;

4.explain
explain 或者 desc 命令获取 MySQL 如何执行 select 语句的信息,包括在 select 语句执行过程中表如何连接和连接的顺序

直接在 select 语句前使用关键字 explain | desc
explain select 字段列表 from 表名 where 条件列表;

在这里插入图片描述

在这里插入图片描述

索引使用

1.最左前缀法则

如果使用了联合索引(索引了多个列),要遵守最左前缀法则

  • 查询从索引的最左列开始,如果 where 部分没有最左边那列,那么索引失效
  • 如果有最左边的列,但是中间跳过了某个字段,那么从这个字段后的所有索引不生效

接下来通过案例演示与分析:

show index from table tb_user;

在这里插入图片描述
有一组聚合索引 (profession、age、status)

– 完整索引执行计划
explain select * from tb_user where profession = ‘软件工程’ and age = 31 and status = ‘0’;
– 舍弃末尾的字段
explain select * from tb_user where profession = ‘软件工程’ and age = 31;
– 只保留最左边的字段
explain select * from tb_user where profession = ‘软件工程’;

在这里插入图片描述
以上的这三组测试中,我们发现只要联合索引最左边的字段 profession存在,索引就会生效,只不 过索引的长度不同。 而且由以上三组测试,我们也可以推测出profession字段索引长度为47、age 字段索引长度为2、status字段索引长度为5

– 没有最左边的列
explain select * from tb_user where age = 31 and status = ‘0’;
explain select * from tb_user where status = ‘0’;
explain select * from tb_user where age = 31;
– 中间跳过一列,索引部分生效
explain select * from tb_user where profession = ‘软件工程’ and status = ‘0’;

上面三组测试,因为不满足最左前缀法则,聚合索引最左边的列不存在,所以索引未生效

下面的这组测试,有最左边的那列,但是跳过了一列,所以后面的索引未生效 >> 索引长度就为 47
在这里插入图片描述
最左前缀法则指的是在执行 DQL 语句时,where 条件部分联合索引最左边的字段必须存在,与条件的先后顺序无关。

2.范围查询

联合索引中,出现范围查询 (>,<),范围查询右侧的列索引失效

– 范围查询使用了 > | <,范围查询右侧的索引失效
explain select * from tb_user where profession = ‘软件工程’ and age > 30 and status = ‘0’;
– 范围查询使用了 >=、<= 时,是不会出现索引失效的
explain select * from tb_user where profession = ‘软件工程’ and age >= 30 and status = ‘0’;

在这里插入图片描述

3.索引失效情况

(1)在索引列上进行运算操作,索引将失效

– 当根据 phone 字段进行等值匹配查询时,索引生效
explain select * from tb_user where phone = ‘17799990015’;
– 当根据 phone 字段进行函数运算操作之后,索引失效
explain select * from tb_user where substring(phone, 12, 2) = ‘15’;

在这里插入图片描述
(2)字符串类型字段使用时,不加引号,索引将失效

– 使用单引号和不使用单引号的聚合索引
explain select * from tb_user where profession = ‘软件工程’ and age = 31 and status = ‘0’;
explain select * from tb_user where profession = ‘软件工程’ and age = 31 and status = 0;
– 使用单引号和不使用单引号的常规索引
explain select * from tb_user where phone = ‘17799990015’;
explain select * from tb_user where phone = 17799990015;

在这里插入图片描述
对于字符串不加单引号,对于查询结果没有什么影响,但是数据库存在隐式类型转换,索引将失效。

(3)如果仅仅是尾部模糊查询,索引不会失效,如果是头部模糊查询匹配,则索引失效

– 模糊匹配,首部模糊失效、尾部模糊索引不失效
explain select * from tb_user where profession like ‘软件%’;
explain select * from tb_user where profession like ‘%工程’;
explain select * from tb_user where profession like ‘%工%’;

在这里插入图片描述
在 like 模糊查询中,在关键字后面加 %,索引可以生效。但是在关键字前面加了%,索引将会失效
(4)用 or 分割的条件,如果 or 前面的列有索引,而后面的列中没有索引,那么设计的索引都不会被用到

explain select * from tb_user where id = 10 or age = 23;
– 特意试一下让没有索引的字段放在 or 前面,有索引的字段放在 or 后面
explain select * from tb_user where age = 23 or id = 10;
explain select * from tb_user where phone = ‘17799990017’ or age = 23;

在这里插入图片描述

– 我们可以对 age 字段建立索引测试:
create index age_index on tb_user(age);
– 再次测试
explain select * from tb_user where id = 10 or age = 23;

总结,当 or 连接的条件,左右两侧字段都有索引时,索引才会生效
在这里插入图片描述
(5)如果 MySQL评估使用索引比全表更慢,则不使用索引

– MySQL 评估使用索引比全表搜索更慢的情况下,那么就不会使用索引
explain select * from tb_user where phone >= ‘17799990005’;
explain select * from tb_user where phone >= ‘17799990015’;

在这里插入图片描述
经过测试我们发现,相同的SQL语句,只是传入的字段值不同,最终的执行计划也完全不一样,这是为 什么呢? 就是因为MySQL在查询时,会评估使用索引的效率与走全表扫描的效率,如果走全表扫描更快,则放弃 索引,走全表扫描。 因为索引是用来索引少量数据的,如果通过索引查询返回大批量的数据,则还不 如走全表扫描来的快,此时索引就会失效

– 查看 is null 与 is not null 操作是否走索引
explain select * from tb_user where profession is null;
explain select * from tb_user where profession is not null;

在这里插入图片描述
查询时MySQL会评估,走索引快,还是全表扫描快,如果全表 扫描更快,则放弃索引走全表扫描。 is null 、is not null是否走索引,得具体情况具体 分析,并不是固定的

4.SQL 提示

mysql复制代码-- 查询 profession = ‘软件工程’ 的执行计划会用哪个索引
explain select * from tb_user where profession = ‘软件工程’;
– 为 profession 列创建常规索引
create index profession_index on tb_user(profession);
– 再次进行测试
explain select * from tb_user where profession = ‘软件工程’;

在这里插入图片描述
测试结果,我们可以看到,possible_keys中 pas,profession_index 这两个索引都可能用到,最终MySQL选择了 pas 索引。这是MySQL自动选择的结果
如果我们想指定使用哪个索引,或者不想用哪个索引就要用到 MySQL 中的 SQL 提示啦

  • SQL 提示是优化数据库的一个重要手段,就是在 SQL 语句中加入一些人为的提示来达到优化操作的目的
  • 相关语法:

– use index: 建议 MySQL 使用哪一个索引完成此次查询[建议不一定生效,mysql 内部会进行评估]
explain select * from tb_user use index(profession_index) where profession = ‘软件工程’;
– ignore index: 忽略指定的索引
explain select * from tb_user ignore index(profession_index) where profession = ‘软件工程’;
– force index: 强制使用索引
explain select * from tb_user force index(profession_index) where profession = ‘软件工程’

在这里插入图片描述

5.覆盖索引

什么是覆盖索引?

  • 查询使用了索引,并且需要返回的列在该索引中已经全部能够找到
  • 尽量使用覆盖索引,减少 select * 的使用,减少回表操作,提高效率

– 推荐使用覆盖索引,不用回表
explain select id, profession from tb_user where profession = ‘软件工程’ and age = 31 and status = ‘0’ ;
explain select id,profession,age, status from tb_user where profession = ‘软件工程’ and age = 31 and status = ‘0’ ;
explain select id,profession,age, status, name from tb_user where profession = ‘软件工程’ and age = 31 and status = ‘0’ ;
explain select * from tb_user where profession = ‘软件工程’ and age = 31 and status= ‘0’;

在这里插入图片描述
我们可以看到四条 SQL 语句的执行计划前面所有的指标都是一样的,只有 Extra 部分是不同的
在这里插入图片描述
为,在tb_user表中有一个联合索引 pas,该索引关联了三个字段 profession、age、status,而这个索引也是一个二级索引,所以叶子节点下面挂的是这一行的主 键id。 所以当我们查询返回的数据在 id、profession、age、status 之中,则直接走二级索引 直接返回数据了。 如果超出这个范围,就需要拿到主键id,再去扫描聚集索引,再获取额外的数据了,这个过程就是回表。 而我们如果一直使用select * 查询返回所有字段值,很容易就会造成回表查询(除非是根据主键查询,此时只会扫描聚集索引)

如果查询中使用了索引,同时 Extra 列为空,可能有以下几种原因:

1.索引的选择性较低:当需要从表中查询的记录数量很多时,索引选择性会降低,此时 MySQL 仍会使用索引,但会放弃使用索引的排序功能,因此 Extra 列会显示为空。
2.查询的结果集太小:如果查询的结果集很小,MySQL 可能会选择全表扫描而不使用索引,因为全表扫描可能比使用索引更快。在这种情况下,Extra 为 NULL 是正常的。
3.没有使用索引的特殊功能:如果查询使用的索引支持某些特殊的功能,如覆盖索引(Covering Index)、索引合并(Index Merge)等,MySQL 仍然会使用索引,但 Extra 列不会显示特殊功能的相关信息,因此会显示为空。

如果对覆盖索引和回表查询不是很理解,可以看看下面几张图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们思考一个问题一张表, 有四个字段(id, username, password, status), 由于数据量大, 需要对 以下SQL语句进行优化, 该如何进行才是最优方案:
select id,username,password from tb_user where username = ‘zhangsan’;
答:针对 username、password 建立联合索引,create index sp on user(username, password);因为这样做可以避免上述 SQL 在查询的过程中出现回表查询

6.前缀索引

当字段类型为字符串(varchar, text, longtext等)时,有时候需要索引很长的字符串,索引空间变大意味着查询时浪费大量的磁盘 IO,影响查询效率,所以我们可以将字符串的一部分前缀建立索引,这样可以大大节省索引空间,从而提升索引效率
(1) 语法格式

create index index_name on table_name(column(n))
– 为 email 设置前缀索引
create index email_index on tb_user(email(5));
– 查看当前 tb_user 的所有索引
show index from tb_user;

在这里插入图片描述
(2)前缀长度

可以根据索引的选择性来决定,而选择性是指不重复的索引值(基数)和数据表的记录总数的比值, 索引选择性越高则查询效率越高, 唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的 [一列去重后记录数 / 总记录数]

select count(distinct email) / count() from tb_user;
select count(distinct substring(email, 1, 5)) / count(
) from tb_user;

(3)前缀索引的查询流程

在这里插入图片描述

7.单列索引与联合索引

  • 单列索引:一个索引只包含单个列
  • 联合索引:一个索引包含多个列

在and连接的两个字段 phone、name上都是有单列索引的,但是 最终mysql只会选择一个索引,也就是说,只能走一个字段的索引,此时是会回表查询的
但是,我们再来创建一个phone和name字段的联合索引,查询时,就走了联合索引,而在联合索引中包含 phone、name的信息,在叶子节点下挂的是对 应的主键id,所以查询是无需回表查询的,这样就可以提升查询效率

在这里插入图片描述

索引设计原则

  • 针对于数据量较大,且查询比较频繁的表建立索引
  • 针对于常作为查询条件(where)、排序(order by) 、分组(group by) 操作的字段建立索引
  • 见谅选择分区度高的列作为索引,尽量建立唯一索引,分区度越高,使用索引的效率越高
  • 如果是字符串类型的字段,字段的长度较长,针对于字段的特点,建立前缀索引
  • 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提升查询效率
  • 要控制索引的数量,索引不是多多益善,索引越多,维护索引结构的代价也越大,会影响增删改的效率
  • 如果索引列不能存储 NULL 值,请在创建表时使用 NOT NULL 约束它。当优化器知道每列是否包含 NULL 值时,它可以更好地确定哪一索引最有效地用于查询

网络安全学习路线图

最后,给大家分享一个超棒的网络安全学习路线图(文末有高清图和XMIND文件)

点击此处即可免费获得282G网络安全学习资源

在这里插入图片描述

还有一些学习中收集的视频、文档资源,有需要的可以自取:
每个成长路线对应板块的配套视频:
在这里插入图片描述

在这里插入图片描述
当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。
在这里插入图片描述

点击此处即可领取282G网络安全学习籽料

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1084911.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis实现简易消息队列的三种方式

Redis实现简易消息队列的三种方式 消息队列简介 消息队列是一种用于在计算机系统中传递和处理数据的重要工具。如果你完全不了解消息队列&#xff0c;不用担心&#xff0c;我将尽力以简单明了的方式来解释它。 首先&#xff0c;想象一下你正在玩一个游戏&#xff0c;而游戏中…

怎么把heic改成jpg?方法大全在这里

怎么把heic改成jpg&#xff1f;HEIC是一种现代的图像文件格式。它是由ISO制定的标准&#xff0c;并得到了苹果公司的支持和推广。与JPG等传统图像格式相比&#xff0c;HEIC格式可以提供更好的图像质量&#xff0c;并且占用更少的存储空间。这使得它在手机、平板电脑和其他移动设…

Java中在循环体内拼接字符串时为什么使用StringBuilder而不是String

在循环体内拼接字符串时为什么使用StringBuilder而不是String 在《阿里巴巴Java开发手册》一书中提到了&#xff1a; 循环体内&#xff0c;字符串的连接方式&#xff0c;请使用 StringBuilder 的 append 方法进行扩展。&#xff08;而不要用String的方式&#xff09; 说明&…

解决IP地址欺骗的网络安全策略

随着互联网的不断发展&#xff0c;网络安全已经成为企业和个人关注的重要问题。其中&#xff0c;IP地址欺骗是一种常见的威胁&#xff0c;它可能导致数据泄露、身份伪装和网络攻击。 1. 使用防火墙和入侵检测系统 防火墙和入侵检测系统&#xff08;IDS&#xff09;是网络安全…

Sui的动态可组合NFT为Cosmocadia增加游戏趣味性

的新游戏Cosmocadia展示了Sui NFT如何在游戏中四处走动&#xff0c;种植和收获蔬菜&#xff0c;并在工作台上制作工具和家具。未来将更新利用NFT&#xff0c;如私人土地&#xff0c;甚至让玩家将他们的SuiFrens NFT带入游戏中。 Lucky Kat Studios的产品经理Bente Bolland将Co…

神奇的代码恢复工具

文章目录 概述工具展示工具下载地址运行过程附件待恢复代码 概述 小C是一名程序猿&#xff0c;他有好多新奇的点子&#xff0c;也乐于把这些变成文字分享给大家。这些分享大部分都与代码相关&#xff0c;在文章里面把这些代码全部按本来的结构展示出来也不是一件容易的事&…

LMI FocalSpec 3D线共焦传感器 使用笔记1

一.硬件介绍 以上特别注意: 屏蔽线必须接地,因为在现场实际调试中,使用软件调试发现经常 弹窗 传感器丢失警告!! 以上 Position LED 的灯被钣金挡住,无法查看异常现象,能否将指示灯设置在软件界面上? 需要确认是软触发还是硬触发,理论上 硬触发比软触发速度要快.(我们目前使用…

Zilliz X Dify.AI ,快速打造知识库 AI 应用

Zilliz 大模型生态矩阵再迎新伙伴&#xff01;近日&#xff0c;Zilliz 和 Dify.AI 达成合作&#xff0c;Zilliz 旗下的产品 Zilliz Cloud、Milvus 与开源 LLMOps 平台 Dify 社区版进行了深度集成。 01.Zilliz Cloud v.s. Dify Dify 作为开源的 LLMs App 技术栈&#xff0c;在此…

[GXYCTF2019]BabyUpload - 文件上传+绕过(后缀文件类型文件内容.htaccess)

[GXYCTF2019]BabyUpload 解题流程 解题流程 1、上传一句话&#xff0c;提示“后缀不允许ph” 2、修改后缀为jpg&#xff0c;提示“上传类型也太露骨了吧&#xff01;” 3、修改类型为image/jpeg&#xff0c;提示“诶&#xff0c;别蒙我啊&#xff0c;这标志明显还是php啊” 4、…

【Axure教程】将figma导入Axure

Figma和Axure是两个不同的界面设计工具&#xff0c;Figma主要用于创建和协作设计图形界面&#xff08;UI&#xff09;&#xff0c;允许多个设计师和利益相关者同时在云端协作设计项目&#xff1b;Axure是原型设计工具&#xff0c;专注于创建高保真、可交互的原型。大家可以根据…

Java学习笔记(一)——概述

目录 一、Java概述 &#xff08;一&#xff09;Java技术体系平台 &#xff08;二&#xff09;Java重要特点 &#xff08;三&#xff09;Java运行机制及运行过程 &#xff08;四&#xff09;JDK &#xff08;五&#xff09;JRE 二、Java的快速入门 &#xff08;一&#…

掌握Python机器学习:空间模拟与时间预测的实战指南

了解全文点击:《掌握Python机器学习&#xff1a;空间模拟与时间预测的实战指南》 文章目录 一、机器学习原理与概述二、Python编译工具组合安装教程三、掌握Python语法及常见科学计算方法四、机器学习数据清洗五、机器学习与深度学习方法六、机器学习空间模拟实践操作七、机器…

6数据层相关框架-基本

MyBatis常见面试问题&#xff0c;以及和hibernate 的区别等_mybatis和hiberbate区别面试_my_styles的博客-CSDN博客*1、什么是MyBatis&#xff1f;*答&#xff1a;MyBatis是一个可以自定义SQL、存储过程和高级映射的持久层框架。*2、讲下MyBatis的缓存*答&#xff1a;MyBatis的…

实现即时沟通与协作的全功能IM即时通讯系统

在当今竞争激烈的商业环境中&#xff0c;高效的沟通和协作成为企业取得成功的关键。在过去&#xff0c;电子邮件和电话等传统工具是企业之间进行沟通和协作的重要手段&#xff0c;然而&#xff0c;随着科技的发展和社交化的趋势&#xff0c;IM即时通讯系统正逐渐成为企业协作的…

虹科方案 | 虹科ATTO 4K/8K以太网解决方案

一、方案背景 以太网为中小型媒体制作工作室提供经济高效的共享存储解决方案。尽管 10GbE 继续在 4K 工作流程中发挥重要作用&#xff0c;但 8K 等新格式需要额外的带宽。 为了使您的环境适应未来的新制作格式&#xff0c;需要一种更强大、低延迟的连接技术&#xff0c;一种足…

外卖点餐小程序源码 扫码点餐小程序源码

外卖点餐小程序源码 扫码点餐小程序源码 吃饭点外卖&#xff0c;坐车靠窗边&#xff0c;睡觉侧着身&#xff0c;洗澡要放歌&#xff0c;随时随地要自拍.......这些俨然早已成为我们当代新青年的真实生活写照。 近年来外卖行业蓬勃发展&#xff0c;外卖小哥走街串巷&#xff0…

FastAPI学习-26 并发 async / await

前言 有关路径操作函数的 async def 语法以及异步代码、并发和并行的一些背景知识 async 和 await 关键字 如果你正在使用第三方库&#xff0c;它们会告诉你使用 await 关键字来调用它们&#xff0c;就像这样&#xff1a; results await some_library()然后&#xff0c;通…

竞赛 深度学习 机器视觉 人脸识别系统 - opencv python

文章目录 0 前言1 机器学习-人脸识别过程人脸检测人脸对其人脸特征向量化人脸识别 2 深度学习-人脸识别过程人脸检测人脸识别Metric Larning 3 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习 机器视觉 人脸识别系统 该项目…

JVM第三讲:JVM 基础-字节码的增强技术详解

JVM 基础-字节码的增强技术详解 本文是JVM第三讲&#xff0c;JVM 基础-字节码的增强技术。在上文中&#xff0c;着重介绍了字节码的结构&#xff0c;这为我们了解字节码增强技术的实现打下了基础。字节码增强技术就是一类对现有字节码进行修改或者动态生成全新字节码文件的技术…

CV计算机视觉每日开源代码Paper with code速览-2023.10.12

精华置顶 墙裂推荐&#xff01;小白如何1个月系统学习CV核心知识&#xff1a;链接 点击CV计算机视觉&#xff0c;关注更多CV干货 论文已打包&#xff0c;点击进入—>下载界面 点击加入—>CV计算机视觉交流群 1.【目标检测】A Novel Voronoi-based Convolutional Neura…