存储引擎、索引(MySQL笔记第四期)

news/2025/2/26 1:00:19

p.s.这是萌新自己自学总结的笔记,如果想学习得更透彻的话还是请去看大佬的讲解

目录

  • 存储引擎概念
    • InnoDB存储引擎
    • MyISAM存储引擎
    • Memory存储引擎
    • 存储引擎的选择
  • 索引
    • 三种索引
    • 索引分类
    • 语法(创建/查看/删除)
    • 性能分析工具
      • SQL执行频率
      • 慢查询日志
      • profile详情
      • explain执行计划
    • 索引的使用规则(及失效情况)
      • 最左前缀法则
      • 范围查询失效情况
      • 索引列运算
      • 字符串不加引号
      • 模糊查询
      • or连接的条件
      • 数据分布的影响
      • SQL提示
      • 覆盖索引
      • 前缀索引
      • 单列索引/联合索引
      • 索引设计原则

存储引擎概念

在这里插入图片描述

存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式,存储引擎是基于表的,而不是基于库的,所以一个库里的多张表可能使用不同的存储引擎,所以存储引擎也被称为表类型

-- 查询建表语句(查询表用的引擎,默认为InnoDB)
show create table account;

在创建表时,指定存储引擎

CREATE TABLE 表名(
       字段1  字段1类型[COMMENT 字段1注释],
       字段2  字段2类型[COMMENT 字段2注释],
       字段3  字段3类型[COMMENT 字段3注释],
       字段n  字段n类型[COMMENT 字段n注释]
)ENGINE=INNODB [COMMENT 表注释];

查看当前数据库支持的引擎:SHOW ENGINES;

InnoDB存储引擎

InnoDB是一种兼顾高可靠性和高性能的通用存储引擎,在MySQL5.5之后InnoDB时默认的MySQL存储引擎
特点:
DML操作遵循ACID模型,支持事务
行级锁,提高并发访问性能
支持外键约束,保证数据的完整性和准确性
在这里插入图片描述

MyISAM存储引擎

MyISAM是MySQL早期的默认储存引擎
特点
不支持事务、外键
支持表锁,不支持行锁
访问速度快

Memory存储引擎

Memory引擎的表数据是存储在内存中的,由于受到硬件问题,或断电问题的影响,只能将这些表作为临时表或者缓存表使用
特点
内存存放
hash索引(默认)

在这里插入图片描述

存储引擎的选择

在选择存储引擎的时候,应该根据应用系统的特点选择合适的存储引擎。对于复杂的应用系统,还可以根据实际情况选择多种存储引擎进行组合
.
InnoDB:是MySQL的默认存储引擎,支持事务、外键,如果应用对于事物的完整性有比较高的要求,在并发条件下要求数据的一致性,数据操作除了插入和查询之外,还包含很多的更新、删除操作,那InnoDB存储引擎是很适合的操作
MyISAM:如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事物的完整性、并发性要求不是很高,那么选择这个存储引擎是非常合适的
Memory:将所有数据保存在内存中,访问速度快,通常用于临时表及缓存,Memory的缺陷是对表的大小有限制,太大的表无法缓存在内存中,而且无法保障数据的安全性
看看大佬讲InnoDB和MyISAM
看看大佬讲Memory

索引

索引是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法。这种数据结构就是索引
在这里插入图片描述

MySQL的索引是在存储引擎层实现的,不同的存储引擎有不同的结构
在这里插入图片描述
在这里插入图片描述



三种索引

在这里插入图片描述
在这里插入图片描述

B+Tree特点:数据都在叶子节点上;叶子节点会形成一个单向链表
.
.
MySQL索引数据结构对经典的B+Tree进行了优化,在原B+Tree的基础上,增加了一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+Tree,提高区间访问的性能,即
在这里插入图片描述
.
.
.
Hash索引就是采用一定的哈希算法,将键值换算为新的hash值,映射到对应的槽位上,然后存储在哈希表中
如果两个或多个键值映射到了一个相同的槽位上,它们就产生了hash冲突(也成为hash碰撞),可以通过链表来解决

Hash索引特点
Hash索引只能用来对等比较(=、in),不支持范围查询(between、>、<、…)
无法用索引完成排序操作(无序)
查询效率高,通常一次检索即可,效率通常高于B+Tree索引

在MySQL中,支持Hash索引的是Memory引擎,而InnoDB具有自适应Hash功能,Hash索引是存储引擎根据B+Tree索引在指定条件下自动构建的

InnoDB引擎选择B+Tree索引结构的原因
相较于二叉树,层级更少,搜索效率更高
对于B-Tree,无论是叶子节点还是非叶子节点都会保存数据,这样导致一页中存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低
相对于Hash索引,B+Tree索引结构支持范围匹配和排序条件

索引分类

在这里插入图片描述
在这里插入图片描述
聚集索引选取规则
如果存在主键,那么主键索引就是聚集索引
如果不存在主键,那么将使用第一个唯一索引作为聚集索引
如果没有主键,也没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引
在这里插入图片描述
如果执行select * from ueser where name = 'Arm';则会执行回表查询·:即先通过二级索引找到对应的主键,再通过聚集索引和找到的主键来找到这一行的数据

语法(创建/查看/删除)

创建索引:CREATE [ UNIQUE | FULLTEXT ] INDEX 索引名 ON 表名 (要添加索引的字段名,...);
单列索引:一个索引关联了一个字段
联合索引:一个索引关联的多个字段

查看索引:SHOW INDEX FROM 表名;

删除索引:DROP INDEX 索引名 ON 表名;

举例

create table worker(
                       name char(3) comment '姓名',
                       phone char(11) comment '手机号',
                       age tinyint unsigned comment '年龄',
                       profession varchar(4) comment '职称',
                       gender char(1) comment '性别',
                       email varchar(16) comment '邮箱地址'
);

insert into worker values ('张三',123456,18,'经理','男','1122@123.com'),
                          ('李四',698547,20,'员工','女','2265@125.com'),
                          ('王五',642851,19,'员工','女','123365@123.com'),
                          ('张三',125462,25,'保安','男','1652@125.com');

show index from worker;

-- 为name字段创建索引(可重复)
create index index_worker_name on worker(name);

-- 为phone创建唯一索引
create unique index index_worker_phone on worker(phone);

-- 为age、profession、gender创建联合索引
create index idx_worker_age_pro_ged on worker(age,profession,gender);

-- 为email创建合适的索引来提高查询效率
create index idx_worker_email on worker(email);

-- 删除索引
drop index idx_worker_email on worker;

性能分析工具

SQL执行频率

通过SQL执行频率,我们可以更好地进行SQL优化,从而提高数据库性能

MySQL客户端连接成功后,通过show [session|global] status命令可以提供服务器状态指令。通过如下指令,可以查看当前数据库增删改查语句的访问频次
SHOW GLOBAL STATUS LIKE 'Com_______';

慢查询日志

通过慢查询日志,我们可以查清楚哪些语句执行效率较低,从而对语句进行更细致的优化,最终提高数据库性能

慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10秒)的所有SQL语句的日志
大佬内容

profile详情

有些SQL语句业务简单,但执行时间较长,这条SQL语句效率相对较低,需要优化

show profiles能够在SQL优化时帮助我们了解时间都耗费到哪里去了。通过have_profiling参数,能够看见当前MySQL是否支持profile操作:SELECT @@have_profiling;
profiling默认关闭,可以通过SET语句在session/global级别开启profiing;
show profiles;:查看每一条SQL语句的耗时基本情况
show profile for query query _id;:查看指定query _id的SQL语句的耗时情况
show profile cpu for query query _id;`:查看指定query _id的SQL语句CPU的使用情况

explain执行计划

explain或desc命令获取MySQL如何执行SELECT语句的信息,包括SELECT语句执行过程中表如何连接以及连接的顺序,从而评判SQL语句的性能
语法:在任意的SELECT语句前面加上EXPIAIN或DESC

explain执行计划各字段含义
.
id:select查询的序列号,表示查询中执行select子句或者是操作表的顺序(id相同,执行顺序从上到下;id不同,值越大,越先执行)
.
select_type:表示select的类型常见的取值有SIMPLE(简单表,即不使用表连接或者子查询)、PRIMARY(主查询,即外层的查询)、UNION(UNION中的第二个或者后面的查询语句)、SUBQUERY(SELECT/WHERE之后包含了子查询)等
.
type:表示连接类型,性能由好到差的连接类型为:NULL(不访问表查询)、system(访问系统表查询)、const(根据主键或者唯一索引查询)、eq_ref、ref(根据非唯一索引查询)、range、index(用了索引)、all(全盘查询)
.
possible_key:显示可能应用在这张表上的索引,一个或多个
.
key:实际使用的索引,如果为NULL,则没有使用索引
.
key_len:表示索引中使用的字节数,该值为索引字段最大可能长度,并非实际使用长度,再不损失精确度的情况下,长度越短越好
.
rows:MySQL认为必须要执行查询的行数,在InnoDB引擎的表中是一个估计值,可能并不总是准确的
.
filtered:表示返回结果的行数占需读取行数的百分比,filtered的值越大越好

索引的使用规则(及失效情况)

最左前缀法则

如果索引了多列(联合索引),要遵守最左前缀法则。最左前缀法则指的是从查询从索引的最左列开始,并且不跳过索引中的列,如果跳跃某一列,则索引部分失效(后面的字段索引失效)

举例

-- 索引长度为26
explain select * from worker where age=18 and profession='经理' and gender='男';

-- 索引长度为21
explain select * from worker where age=18 and profession='经理' ;

-- 索引长度为2
explain select * from worker where age=18;

-- 未遵循最左前缀法则,索引全部失效
explain select * from worker where  profession='经理' and gender='男';

-- 未遵循最左前缀法则,索引部分失效(索引长度为2)
explain select * from worker where age=18 and  gender='男';

-- 索引长度为26(即最左前缀法则只看索引是否存在,与SQL语句中索引位置无关)
explain select * from worker where profession='经理' and gender='男' and age=18;

范围查询失效情况

联合索引中出现范围查询(>,<)时范围查询右侧的索引会失效(可使用>=,<=规避问题)
举例

-- 索引长度为2
explain select * from worker where age>17 and profession='经理' and gender='男';

-- 索引长度为2(与SQL语句中索引位置无关)
explain select * from worker where profession='经理' and gender='男' and age>17;

-- 索引长度为26
explain select * from worker where age>=17 and profession='经理' and gender='男';

索引列运算

不要再索引列上进行运算操作,否则索引会失效
举例

-- 索引长度为67
explain select * from worker where email='1122@123.com';

-- 索引失效(因为对索引列进行了运算)
explain select * from worker where substring(email,2,2) = 12;

字符串不加引号

字符串类型字段使用时不加引号,索引将失效
举例

-- 索引失效
explain select * from worker where phone=123456;

模糊查询

如果仅仅是尾部模糊匹配,索引不会失效;如果是头部模糊匹配,索引失效。
举例

-- 索引长度为45
explain select * from worker where phone like '12____';

-- 索引长度为45
explain select * from worker where phone like '12__56';

-- 索引失效
explain select * from worker where phone like '____56';

-- 索引失效
explain select * from worker where phone like '%34__';

or连接的条件

用or分割开的条件,所有条件中的列都需要有索引,否则涉及的索引都不会用到(即失效)
举例

-- 删除索引
drop index idx_worker_email on worker;

-- -----------------------------------------------------------------------

-- 索引失效
explain select * from worker where phone='123456' or email='1122@123.com';

-- 索引失效
explain select * from worker where email='1122@123.com' or phone='123456';

-- 索引长度分别为45,13
explain select * from worker where phone='123456' or name='张三';

数据分布的影响

如果MySQL评估使用索引比全表更慢,则不使用索引
举例

-- 索引失效,走的是全盘扫描
explain select * from worker where age>=0;

-- 索引失效,走的是全盘扫描
explain select * from worker where phone is not null;

SQL提示

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

关于索引的**(即当字段的索引有多种的时候,人为地让数据库使用特定的索引)**

use index():告诉数据库应该使用哪种索引(有可能不听你的)

ingore index():告诉数据库应该忽略哪种索引

force index():告诉数据库必须使用哪种索引

举例

explain select * from worker use index(idx_worker_age) where age=18;

explain select * from worker ignore index(idx_worker_age) where age=18;

explain select * from worker ignore index(index_worker_name) where name='张三';

explain select * from worker force index(idx_worker_age) where age=18;

覆盖索引

尽量使用覆盖索引(查询使用了索引,并且所需返回的列,在该索引中已经能全部找到),减少select *的使用
举例

-- Extra显示Using index condition
explain select * from worker where age = 18 and profession = '张三' and gender = '男';

-- Extra显示Using where; Using index
explain select age,profession,gender from worker where age = 18 and profession = '张三' and gender = '男';

-- Extra显示Using index condition
explain select age,profession,gender,name from worker where age = 18 and profession = '张三' and gender = '男';

Extra显示Using index condition:查找使用了索引,但需要回表查询数据
Extra显示Using where; Using index:查找使用了索引,由于需要的数据都能在索引列中找到,所以不需要回表查询数据
覆盖索引更详细解析

前缀索引

当字段类型为字符串(varchar、text等)时,有时候需要索引很长的字符串,这会让索引变得很大,查询时会浪费大量的磁盘IO,影响查询效率.此时可以只将字符串的一部分进行前缀,建立索引,这样可以大大节约索引空间,从而提高索引效率

创建语法:创建索引:CREATE [ UNIQUE | FULLTEXT ] INDEX 索引名 ON 表名 (字段(n));(n表示前缀的长度)

前缀长度可以根据索引的选择性来决定;而选择性时是指不重复的索引值(基数)和数据表的记录总数的比值。索引的选择性越高查询效率越高
唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的

举例

-- 由于phone字段的是唯一索引,因此选择性为1
select count(distinct phone) / count(*) from worker;

-- 选择性为1
select count(distinct substring(phone,1,3)) / count(*) from worker;

-- 选择性为0.75
select count(distinct substring(phone,1,2)) / count(*) from worker;

由于前缀索引的长度以及选择性是呈反比关系,所以在使用时要进行取舍

单列索引/联合索引

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

在业务场景中,如果存在多个查询条件,考虑针对于查询字段建立索引时,建议联合索引,而非单列索引

多条件联合查询时,MySQL优化器会评估哪个字段的查询效率更高,会选择该索引完成本次查询

索引设计原则

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


http://www.niftyadmin.cn/n/5867009.html

相关文章

力扣hot100刷题——11~20

文章目录 11.滑动窗口最大值题目描述思路&#xff1a;滑动窗口单调队列code 12.最小覆盖子串题目描述思路&#xff1a;双指针/滑动窗口哈希code Ⅰcode Ⅱ 13.最大子数组和题目描述思路&#xff1a;dp/贪心code 14.合并区间题目描述思路&#xff1a;贪心code 15.轮转数组题目描…

SpringSecurity处理器:登录成功处理器、登录失败处理器、无权限处理器、注销成功处理器

在 Spring Security 中,你可以通过实现特定的接口或扩展某些类来自定义各种处理器,例如登录成功处理器、登录失败处理器、无权限处理器和登出成功处理器。 以下是每种处理器的具体实现方法: 【示例】首先创建统一的响应结果类和响应结果编码枚举,方便后续示例中使用。 (…

2025-skywalking组件

历史版本下载地址&#xff1a;Apache Archive Distribution Directory 官网&#xff1a;Apache SkyWalking 目录 . webapp: UI前端(web 监控页面)的jar包和配置文件; . oap-libs:后台应用的jar包&#xff0c;以及它的依赖jar包&#xff0c;里边有一个server-starter-*.jar就是…

API返回的数据结构包含哪些字段?

淘宝商品详情API返回的数据结构较为复杂&#xff0c;具体字段会根据API的版本和请求参数有所不同。以下是基于最新搜索结果的API返回值字段说明&#xff1a; 基础字段 num_iid&#xff1a;商品的唯一标识ID。 title&#xff1a;商品标题&#xff0c;用于描述商品名称或特点。…

C++:pthread线程分离和线程属性

在 C 的多线程编程中&#xff0c;pthread 库提供了强大的功能来管理线程。其中&#xff0c;线程分离和线程属性是两个重要的概念&#xff0c;它们对于优化线程的行为和资源管理有着关键作用。 线程分离 1.1 什么是线程分离 在 pthread 库中&#xff0c;线程有两种状态&#…

从零开始的网站搭建(以照片/文本/视频信息通信网站为例)

本文面向已经有一些编程基础&#xff08;会至少一门编程语言&#xff0c;比如python&#xff09;&#xff0c;但是没有搭建过web应用的人群&#xff0c;会写得尽量细致。重点介绍流程和部署云端的步骤&#xff0c;具体javascript代码怎么写之类的&#xff0c;这里不会涉及。 搭…

【Qt之QQuickWidget】QML嵌入QWidget中

由于我项目开始使用Widgets,换公司后直接使用QML开发&#xff0c;没有了解过如何实现widget到qml过渡&#xff0c;恰逢面试时遇到一家公司希望从widget迁移到qml开发&#xff0c;询问相关实现&#xff0c;一时语塞&#xff0c;很尴尬&#xff0c;粗略研究并总结下。 对qwidget嵌…

Html 5简介(学习笔记)

基本标签 1. 换行标签 <br> <br>2. 链接标签 <a> <a href"https://www.example.com" target"_blank">网站</a>href&#xff1a;指定链接地址。 target&#xff1a; _blank&#xff1a;在新标签页打开。_self&#xff08…