logo 范 · 拾光录
网址收集 关于作者 Github Gitee
杂文随笔5
Hexo博客:基础使用Hexo博客:Next主题Hexo博客:Next进阶使用Hexo博客:Next高级配置基于Node的WIKI管理
前端知识16
HTML常用知识CSS常用知识CSS美化checkbox复选框JavaScript常用知识JavaScript格式化时间戳JavaScript窗口宽高处理JavaScript黑夜主题切换实现方案JavaScript数字转大写简易图片查看器TypeScript基础知识Threejs基础三要素Threejs网格辅助和轨道控制器Threejs物体绘制Electron基础使用Nodejs基础知识animate.css页面动画
Vue框架19
Vite的使用及扩展Vue3父子组件Vue3使用Marked解析MarkdownMermaid图表生成库初始化页面加载动画Axios表单提交二维码解决方案NProgress加载进度条Vue3动态菜单实现Vue3使用ECharts图表Vue3处理Excel导入导出keep-alive页面缓存及setup问题Element:文件上传Element:结合Pinia实现动态菜单Element:图片上传组件Element:自定义统一弹窗组件Element:表格自定义指令控制按钮显示(鉴权)可视化大屏使用缩放适配分辨率
UniApp15
UniApp的基础使用封装网络请求工具及文件上传uni-app的开发记录微信小程序分享原生文件上传Pinia取消滚动条(兼容小程序)tabbar消息数量显示scroll-view上滑到底部加载数据状态栏高度动态设配数据共享与传递uview-plus导航栏实现背景融合Wot UIWot UI实现顶部背景图融合uni-app x
Java基础知识10
基础知识面向对象Lambda表达式常用API常用知识积累try-with-resource注解反射多线程经纬度距离计算
SpringBoot31
application配置Maven创建聚合项目全局异常处理锁机制项目启动初始化数据方式邮件功能集成原生定时任务异步集成阿里云OSS阿里OSS预签名上传基于hutool读excelJSR303WebSocketWebSocket版AI接口流式调用Smart-Doc接口文档生成器application配置信息加密雪花算法工具AOP实现请求参数脱敏思路JWT生成Token及工具类SpringBoot默认JSON与对象转换若依框架:安装使用若依框架:优化和调整文件上传若依框架:管理后台页面优化若依框架:后端接口代码优化SpringAISpringBoot实现AI接口流式调用服务启动时创建MySQL连接自建项目工程树形结构处理工具微信支付代码微信手机号登录
SpringMVC14
跨域处理拦截器RESTful风格伪前后端分离Jackson转换器调整Thymeleaf基于拦截器做权限校验AOP打印接口请求响应日志AOP打印接口请求响应耗时文件上传和回显POST请求加解密实现(AES)POST请求加解密实现(RSA+AES)参数动态校验实现方案真实IP和归属地
MyBatis8
MyBatis基本使用与配置Mapper使用相关MaBatis多数据源配置MyBatisPlus数据统计类处理方案MyBatisPlus条件查询正向工程的实现(H2)mybatis-plus-join
SpringCloud15
Netflix:微服务与搭建Netflix:服务的消费与提供Netflix:EurekaNetflix:ActuatorNetflix:RibbonNetflix:FeignNetflix:HystrixNetflix:ZuulAlibaba:简介与搭建Alibaba:Nacos注册中心Alibaba:RibbonAlibaba:OpenFeignAlibaba:Nacos配置中心Alibaba:GetewayAlibaba:Sentinel
MySQL6
MySQL基础知识MySQL多表查询与事务MySQL常用函数及解决方案MySQL视图MySQL索引安装MySQL
Redis7
Redis介绍和安装Redis配置文件Redis持久化Redis集群Redis语法基础Redis相关问题及解决方案SpringBoot集成Redis使用记录
MongoDB10
Linux安装MongoDBMongoDB基础语法MongoTemplate及SpringBoot配置MongoTemplate中Update操作MongoTemplate中聚合查询MongoTemplate日期归档示例项目使用相关知识归纳地理位置存储与距离查询MongoDB副本集与事务获取类名和属性名工具类
其他数据库1
H2数据库
Python编程6
Python基础知识Python语法yolo目标检测OpenCV的使用及树莓派平台condauv
工具集合13
IDEAMavenGradleGitNginx安装Nginx配置VSCodeJMeter压测DockerOllamaRustFSPicGoObs录制
Linux知识11
Linux常用命令Jar启动脚本VirtualBox安装CentOSVirtualBox安装Ubuntu树莓派安装及使用frp内网穿透ArchLinux:基础系统安装ArchLInux:图形化界面安装ArchLinux:常用软件ArchLinux:深度优化ArchLinux:Niri
创意设计2
Blender:入门知识UI设计基础知识
AI相关9
Claude CodeHermes AgentOpenAI基本使用OpenAI工具调用OpenAI记忆管理OpenAI推理执行OpenAI开发框架Langchainllama.cpp

索引

对于慢查询来说,首先想到的解决方案就是索引,检查查询字段是否加了索引,以及检查索引是否命中
那么什么是索引?索引就是有顺序的数据结构,能加快数据的查询,没有索引的情况下查询是全表扫描,命中率低,IO次数高,效率慢

索引的数据结构推演

目前MySQL的索引使用的数据结构是B+树,为什么使用B+树?B+树解决了什么问题?可以推演一下

二叉树

对于MySQL索引的数据结构,一开始想到的就是二叉树,查询速度快
比如咱们对下图的数据进行select * from t where col2=89

如果没有索引,该表需要进行6次查询(6次IO),如果加了二叉树,只需要2次查询,效率大大提高
注意:二叉树的排序原理为:每次加一个数据进来都会从根节点进行比较,大的在右边,小的在左边

红黑树

根据上面图可以看出问题,如果查询的是select * from t where col1=6,因为col1的数据递增,所以二叉树为

这样的二叉树对于查询来说依然是6次,效率没有太大提升
解决方案:使用红黑树,红黑树也是一种二叉树,红黑树又叫平衡二叉树,与二叉树不同的是,每次插入数据后会进行平衡,不让树的左右节点出现太长的情况,这样就解决了顺序数据的查询效率问题

B树

但是同样红黑树作为MySQL索引的数据结构还是有问题的,毕竟在MySQL中,数据量是很大的,几百万或几千万的数据形成一颗红黑树,层级太深,对于查询来说,效率同样不是很理想
这个问题想到的解决办法为:多叉,这样的数据结构为B树

B+树

但是对于MySQL,是将B树进行了改进,形成了B+树

这样就达到了在数据大的情况下,树的高度依旧在一个可控的范围
这里需要注意,数据查找时的比较由于是在内存中进行,耗费时间可以忽略不记

B树和B+树的区别

索引分类

名称 说明 特点 关键字
主键索引 针对表中主键创建的索引 默认自动创建,只有一个 primary
唯一索引 避免列值重复 可以多个 unique
常规索引 快速定位特定数据 可以多个
全文索引 查找文本中的关键字 可以多个 fulltext

效率问题:下列查询哪个效率高?

select * from user where id=10
select * from user where name='xx'
备注:id为主键,name字段也创建了索引

说明:对于主键查询直接到聚集索引进行检索即可,而对于常规索引查询需要到二级索引中查询到对应的主键ID,再到聚集索引查询数据,该行为称为回表查询,对应效率较低

索引语法

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

性能分类

SQL执行频率

查询方式:show global status like 'Com_______';,可以查看各类SQL的执行次数,如:

+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Com_binlog    | 0     |
| Com_commit    | 0     |
| Com_delete    | 0     |
| Com_import    | 0     |
| Com_insert    | 2     |
| Com_repair    | 0     |
| Com_revoke    | 0     |
| Com_select    | 27    |
| Com_signal    | 0     |
| Com_update    | 0     |
| Com_xa_end    | 0     |
+---------------+-------+

慢查询日志

慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位秒,默认10)的所有SQL语句的日志
MySQL的慢查询日志默认没有开启,可以使用show VARIABLES like 'slow_query%';查看开启状态,使用show VARIABLES like 'long_query_time';查看慢日志时间
慢日志查询的开启可以临时和永久,临时方式在MySQL重启后失效

set global slow_query_log=ON’;
set global long_query_time=4; # 该设置需要重新建立会话才生效

永久方式为对文件/etc/my.cnf进行配置

# 开启慢查询日志
show_query_log=1
# 设置慢查询时间
long_query_time=2

注意一定要加在以下配置之下,不能放在其他配置之后,会报错

log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

配置后需要重启systemctl restart mysqld,慢日志文件在/var/lib/mysql/*-show.log
如果配置错误无法启动,可以查看启动错误日志cat /var/log/mysqld.log | grep ERROR

小技巧:在控制台查询SQL时字段过多,可以将末尾的;换为\G进行换行展示

profile

对于一些简单的查询SQL,即便设置了慢日志在2s,其执行耗时1.9s也是不好的,可以借助profile进行分析
使用select @@have_profiling;查看数据库是否支持,默认profile是关闭的,可以进行开启

--查看开启状态:0-关闭 1-开启
select @@profiling;
--设置开启状态
set profiling=1;

explain执行计划(重要)

对查询语句前加explain/desc可以查看SQL的执行计划

根据主键或唯一索引查询为const级别,非唯一性索引查询为ref级别

最左前缀法则

在建立多列索引(联合索引)的情况下,如下图,索引有nameageposition三个字段

如果查询的语句为:select * from t where age=18,其实是无法命中索引的
而使用select * from t where name='tom' and age=18就可以命中索引,这是由于联合索引从第一个索引开始命中,没有第一个直接不算命中
原因:直接查询age是无序的,无法进行快速查询,如果name相同那么age就是有序的,就能命中索引

结论:如果索引为联合索引,要遵循最左前缀法则,即查询从索引的最左列开始,并且不能跳过索引中的列,否则后面索引将失效(与查询语句中条件的位置无关,指字段必须存在)

索引失效场景

SQL提示

优化数据库的重要手段,对于多个索引场景,MySQL会自动选择索引,开发人员可以通过指定的方式告诉MySQL使用哪个索引

--语法
select * from user xxx(index_name)
--告诉数据库建议使用的索引,MySQL会比较该索引是否更快,然后采用
use index
--告诉数据库不要使用的索引
ignore index
--告诉数据库必须使用该索引
force index

覆盖索引

前提知识:聚集索引为id索引,叶子节点包含了一整列数据;而二级索引仅包含了索引字段的数据和id 对于查询的列,尽量不要使用select *,而应尽量查找二级索引中叶子节点有的数据,如果二级索引叶子节点没有相关数据,就会发生回表查询操作,即到聚集索引中找相关字段,该操作效率低,10倍以上耗时
而没有发生回表操作的索引查询称为覆盖索引,效率高

实际操作案例:一张表有四个字段(id、username、password、status),由于数据量大,需要对以下SQL进行优化,该如何进行才是最优方案?

select id,username,password from user where username = 'xx'

答:针对username和password创建联合索引,该二级索引下叶子节点有id,就能防止回表查询,提高效率

前缀索引

当字段类型为字符串(varchar,text...)时,对其直接建立索引会导致索引占用空间很大,查询时浪费大量磁盘IO,降低效率,此时可以将字符串的一部分前缀建立索引,节约索引空间,提高效率

--语法
create index idx_xxx on table_name(column(n))

前缀长度:根据索引的选择性决定,选择性指不重复的索引值和数据表的记录总数的比值,索引选择性越高查询效率越高

select count(distinct text) / count(*) from table
select count(distinct substring(text, 1, 5)) / count(*) from table

索引设计原则

索引失效场景总结

https://mp.weixin.qq.com/s/5N71T-kloq-IUQKziB5THA

索引
索引的数据结构推演
二叉树
红黑树
B树
B+树
B树和B+树的区别
索引分类
索引语法
性能分类
SQL执行频率
慢查询日志
profile
explain执行计划(重要)
最左前缀法则
索引失效场景
SQL提示
覆盖索引
前缀索引
索引设计原则
索引失效场景总结