mysql高级三:sql性能优化+索引优化+慢查询日志

news2024/12/26 10:56:41
内容介绍
单表索引失效案例

0、思考题:如果把100万数据插入MYSQL ,如何提高插入效率

(1)关闭自动提交,只手动提交一次

(2)删除除主键索引外其他索引

(3)拼写mysql可以执行的长sql,批量插入数据

(4)使用java多线程

(5)使用框架,设置属性,实现批量插入

1、计算、函数导致索引失效

CREATE INDEX idx_name ON emp (NAME);

EXPLAIN SELECT * FROM emp WHERE emp.name  LIKE 'abc%';

EXPLAIN SELECT * FROM emp WHERE LEFT(emp.name,3) = 'abc'; ----索引失效

2 LIKE以%开头索引失效

EXPLAIN SELECT * FROM emp WHERE NAME LIKE '%ab%'; ----索引失效

3、不等于(!= 或者<>)索引失效

EXPLAIN SELECT * FROM emp WHERE emp.name = 'abc' ;

EXPLAIN SELECT * FROM emp WHERE emp.name <> 'abc' ; ----索引失效

4、IS NOT NULL 和 IS NULL

EXPLAIN SELECT * FROM emp WHERE emp.name IS NULL;

EXPLAIN SELECT * FROM emp WHERE emp.name IS NOT NULL; ----索引失效

5、类型转换导致索引失效

EXPLAIN SELECT * FROM emp WHERE NAME='123';

EXPLAIN SELECT * FROM emp WHERE NAME= 123; ----索引失效

6、全值匹配我最爱

EXPLAIN SELECT * FROM emp WHERE emp.age = 30 AND deptid = 4 AND emp.name = 'abcd';

CREATE INDEX idx_age ON emp(age);

CREATE INDEX idx_age_deptid ON emp(age,deptid);

CREATE INDEX idx_age_deptid_name ON emp(age,deptid,`name`);

7、最佳左前缀法则

EXPLAIN SELECT * FROM emp WHERE emp.age=30 AND emp.name = 'abcd' ;

CREATE INDEX idx_age_name ON emp (age,NAME);

EXPLAIN SELECT * FROM emp WHERE emp.deptid=1 AND emp.name = 'abcd';

EXPLAIN SELECT * FROM emp WHERE emp.age = 30 AND emp.deptid=1 AND emp.name = 'abcd';

CREATE INDEX idx_age_deptid_name ON emp(age,deptid,`name`);

EXPLAIN SELECT * FROM emp WHERE emp.deptid=1 AND emp.name = 'abcd' AND emp.age = 30;

8、索引中范围条件右边的列失效

CREATE INDEX idx_age_deptid_name ON emp(age,deptid,`name`);

EXPLAIN SELECT * FROM emp WHERE emp.age=30 AND emp.name = 'abc' AND emp.deptId>1000 ;

CREATE INDEX idx_age_name_deptid ON emp(age,`name`,deptid);

关联查询优化

1、数据准备

-- 分类

CREATE TABLE IF NOT EXISTS `class` (

`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,

`card` INT(10) UNSIGNED NOT NULL,

PRIMARY KEY (`id`)

);

-- 图书

CREATE TABLE IF NOT EXISTS `book` (

`bookid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,

`card` INT(10) UNSIGNED NOT NULL,

PRIMARY KEY (`bookid`)

);





-- 插入16条记录

INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));



-- 插入20条记录

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

2、左外连接实例

(1)明确角色

(2)优化

EXPLAIN SELECT * FROM class LEFT JOIN book ON class.card = book.card;

CREATE INDEX idx_class_card ON class(card);

CREATE INDEX idx_book_card ON book(card);

*使用LEFT JOIN,前面的是驱动表、后面是被驱动表

针对两张表的连接条件涉及的列,索引要创建在被驱动表上,驱动表尽量是小表

  • 如果驱动表上没有where过滤条件
    • 当驱动表的连接条件没有索引时,驱动表是全表扫描
    • 当针对驱动表的连接条件建立索引时,驱动表依然要进行全索引扫描
    • 因此,此时建立在驱动表上的连接条件上的索引是没有太大意义的
  • 如果驱动表上有where过滤条件,那么针对过滤条件创建的索引是有必要的

3、内连接实例

EXPLAIN SELECT * FROM class INNER JOIN book ON class.card = book.card;

CREATE INDEX idx_class_card ON class(card);

CREATE INDEX idx_book_card ON book(card);

*使用INNER JOIN,驱动表、被驱动表不固定,mysql选择

MySQL优化器也会自动选择驱动表,自动选择驱动表的原则是:索引创建在被驱动表上,驱动表是小表。

4、分析4种查询sql(mysql5)

#1 NO3

EXPLAIN SELECT ab.name,c.`name` ceoname FROM

(SELECT a.`name`,b.`CEO` FROM emp a

LEFT JOIN dept b ON a.`deptId`=b.`id`)ab

LEFT JOIN emp c ON ab.ceo=c.`id`;



#2 NO4

EXPLAIN SELECT c.name,ab.name ceoname FROM emp c LEFT JOIN

(SELECT a.`name`,b.`id` FROM emp a

INNER JOIN dept b ON b.`CEO` = a.`id`)ab

ON c.`deptId`= ab.id;



#3  NO1

 EXPLAIN SELECT a.`name`,c.`name` ceoname FROM emp a

LEFT JOIN dept b  ON a.`deptId`= b.id

LEFT JOIN emp c ON b.`CEO`= c.`id`;



#4  NO2

EXPLAIN SELECT a.`name`,(SELECT c.name FROM emp c WHERE c.id =b.`CEO`)ceoname

 FROM emp a

LEFT JOIN dept b ON a.`deptId`=b.`id`;

5、总结

  • 保证被驱动表的JOIN字段已经创建了索引
  • 需要JOIN 的字段,数据类型保持绝对一致。
  • LEFT JOIN 时,选择小表作为驱动表,大表作为被驱动表 。减少外层循环的次数。
  • INNER JOIN 时,MySQL会自动将小结果集的表选为驱动表 。选择相信MySQL优化策略。
  • 能够直接多表关联的尽量直接关联,不用子查询。(减少查询的趟数)
  • 衍生表建不了索引(MySQL5.5

其他优化

1、子查询优化

(1)获取非掌门人成员

#获取非掌门人成员

CALL proc_drop_index("atguigudb","emp");

CALL proc_drop_index("atguigudb","dept");

SELECT * FROM t_emp a WHERE a.id NOT IN 

(SELECT b.ceo FROM t_dept b WHERE b.ceo IS NOT NULL);

EXPLAIN SELECT * FROM emp a WHERE a.id NOT IN 

(SELECT b.ceo FROM dept b WHERE b.ceo IS NOT NULL);

#子查询优化NOT IN 

EXPLAIN SELECT * FROM emp a LEFT JOIN dept b ON a.id = b.ceo

WHERE  b.id IS NULL;

(2)结论

尽量不要使用NOT IN 或者 NOT EXISTS,用LEFT JOIN xxx ON xx = xx WHERE xx IS NULL替代

2、排序优化

(1)实例

CALL proc_drop_index("atguigudb","emp");

CALL proc_drop_index("atguigudb","dept");

CREATE INDEX idx_age_deptid_name ON emp (age,deptid,`name`);

#无过滤,不索引

EXPLAIN SELECT * FROM emp ORDER BY age,deptid;

EXPLAIN SELECT * FROM emp ORDER BY age,deptid LIMIT 10;

EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY deptid;

#顺序错,不索引

EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY deptid, `name`;

EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY deptid, empno;

CREATE INDEX idx_age_deptid_empno ON emp (age,deptid,`empno`);

EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY `name`, deptid;

EXPLAIN SELECT * FROM emp WHERE deptid=45 ORDER BY age;

#方向反,不索引

EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY deptid DESC, `name` DESC;

EXPLAIN SELECT * FROM emp WHERE age=45 ORDER BY deptid ASC, `name` DESC;

  1. 总结

无过滤,不索引

顺序错,不索引

方向反,不索引

3、mysql索引选择

EXPLAIN SELECT * FROM emp WHERE age =30 AND empno <101000 ORDER BY `name`;

CREATE INDEX idx_age_empno ON emp (age,`empno`);

CREATE INDEX idx_age_name ON emp (age,NAME);

*当【范围条件】和【group by 或者 order by】的字段出现二选一时,优先观察条件字段的过滤数量,如果过滤的数据足够多,而需要排序的数据并不多时,优先把索引放在范围字段上。反之,亦然。

也可以将选择权交给MySQL:索引同时存在,mysql自动选择最优的方案:(对于这个例子,mysql选择idx_age_empno),但是,随着数据量的变化,选择的索引也会随之变化的。

4、双路排序和单路排序

(1)双路排序(慢)

取一批数据,要对磁盘进行两次扫描。众所周知,IO是很耗时的,所以在mysql4.1之后,出现了第二种改进的算法,就是单路排序

(2)单路排序(快)

它的效率更快一些,因为只读取一次磁盘,避免了第二次读取数据。并且把随机IO变成了顺序IO。但是它会使用更多的空间 因为它把每一行都保存在内存中了。

5、分组优化

  • group by 使用索引的原则几乎跟order by一致。但是group by 即使没有过滤条件用到索引,也可以直接使用索引(Order By 必须有过滤条件才能使用上索引)
  • 包含了order bygroup bydistinct这些查询的语句,where条件过滤出来的结果集请保持在1000行以内,否则SQL会很慢。

6、覆盖索引优化

总结

  • 禁止使用select *,禁止查询与业务无关字段
  • 尽量利用覆盖索引

慢查询日志

1、如何对系统查询慢做索引优化

(1)找运维人员开启生产数据库慢查询日志

(2)等待1-2周时间,积累慢查询日志

(3)借助工具获取慢查询次数最多和查询时间最长的几个sql进行优化

(4)在生产数据库,使用EXPLAIN进行sql分析,找到瓶颈,创建索引优化

(5)关闭慢查询日志。

2、是什么

一种日志记录,查看哪些SQL超出了我们的最大忍耐时间值。

3、使用

(1)开启slow_query_log

SET GLOBAL slow_query_log=1;

SHOW VARIABLES LIKE '%slow_query_log%';

(2)修改long_query_time阈值

SHOW VARIABLES LIKE '%long_query_time%'; -- 查看值:默认10秒

SET GLOBAL long_query_time=0.1; -- 设置一个比较短的时间,便于测试

(3)运行sql

(4)查看慢查询日志

(5)使用工具分析慢查询日志

-- 查看mysqldumpslow的帮助信息

mysqldumpslow --help

-- 工作常用参考

-- 1.得到返回记录集最多的10个SQL

mysqldumpslow -s r -t 10 /var/lib/mysql/atguigu-slow.log

-- 2.得到访问次数最多的10个SQL

mysqldumpslow -s c -t 10 /var/lib/mysql/atguigu-slow.log

-- 3.得到按照时间排序的前10条里面含有左连接的查询语句

mysqldumpslow -s t -t 10 -g "left join" /var/lib/mysql/atguigu-slow.log

-- 4.另外建议在使用这些命令时结合 | 和more 使用 ,否则语句过多有可能出现爆屏情况

mysqldumpslow -s r -t 10 /var/lib/mysql/atguigu-slow.log | more

1、单表索引失效案例

2、关联查询优化

3、其他优化

4、慢查询日志

5、视图

6、高性能架构模式

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

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

相关文章

matlab智能算法程序包89套最新高清录制!matlab专题系列!

关于我为什么要做代码分享这件事&#xff1f; 助力科研旅程&#xff01; 面对茫茫多的文献&#xff0c;想复现却不知从何做起&#xff0c;我们通过打包成品代码&#xff0c;将过程完善&#xff0c;让您可以拿到一手的复现过程以及资料&#xff0c;从而在此基础上&#xff0c;照…

CNN成长路:从AlexNet到EfficientNet(02)

一、说明 在~10年的深度学习中&#xff0c;进步是多么迅速&#xff01;早在 2012 年&#xff0c;Alexnet 在 ImageNet 上的准确率就达到了 63.3% 的 Top-1。现在&#xff0c;我们超过90%的EfficientNet架构和师生训练&#xff08;teacher-student&#xff09;。 二、第一阶段 …

白盒测试怎么做

一、什么是白盒测试 白盒测试又称结构测试、逻辑驱动测试或基于代码的测试。 白盒测试是一种测试用例设计方法&#xff0c;盒子指的是被测试的软件&#xff0c;白盒指的是盒子是可视的&#xff0c;即清楚盒子内部的东西以及里面是如何运作的。 "白盒"法需要测试者…

Spring学习笔记——2

Spring学习笔记——2 1、Bean的基本注解开发1.1、注解版本和Component简介1.2、Component使用1.3、Component的三个衍生注解 二、Bean依赖注入注解开发2.1、依赖注入相关注解2.2、Autowired扩展 三、非自定义Bean注解开发四、Bean配置类的注解开发五、Spring注解的解析原理六、…

解决Vue+Element UI使用表单rules国际化时From表单验证信息不能实时更新

说明&#xff1a;该篇博客是博主一字一码编写的&#xff0c;实属不易&#xff0c;请尊重原创&#xff0c;谢谢大家&#xff01; 博主在工作之余开始进行自动化测试平台的开发&#xff0c;虽然已经996一个月了但是还是在使劲挤时间做这件事情&#xff0c;目前平台使用前端框架vu…

mysql再docker中运行,直接在实体机上运行mysql命令初始化数据库数据

背景 项目上我们使用docker安装mysql&#xff0c;项目启动的时候需要利用sql语句初始化数据。 直接在实体上是识别不到mysql命令的。 实现方式 实现方式1&#xff1a;在docker容器内部执行sql语句 1. 将sql文件上传到容器内 docker cp /root/1.sql d5:/home/ 说明&#…

日期格式化的最佳实践:如何在Java中处理日期格式化

文章目录 前言一、使用format()方法二、使用注解JsonFormat三、使用消息转换器1.定义用户类2.重写DateSerializer 方法3.定义对象映射器&#xff1a;4.定义消息转换器5.调用测试 总结 前言 当涉及到日期格式化时&#xff0c;了解正确的方式和最佳实践是至关重要的。 日期格式化…

Stephen Wolfram:ChatGPT 的训练

The Training of ChatGPT ChatGPT 的训练 OK, so we’ve now given an outline of how ChatGPT works once it’s set up. But how did it get set up? How were all those 175 billion weights in its neural net determined? Basically they’re the result of very large…

目标检测与跟踪 (3)- TensorRTYOLO V8性能优化与部署测试

系列文章目录 目标检测与跟踪 &#xff08;1&#xff09;- 机器人视觉与YOLO V8_Techblog of HaoWANG的博客-CSDN博客 目标检测与跟踪 &#xff08;2&#xff09;- YOLO V8配置与测试_Techblog of HaoWANG的博客-CSDN博客 目录 系列文章目录 前言 YOLO v8 TensorRT 一、…

等保三级中“身份鉴别”要求与2FA双因子认证有何关联?

为了保护信息的安全&#xff0c;我国实行对信息及信息载体按照重要性等级分别进行保护&#xff0c;也就是信息安全等级保护制度。根据信息系统在国家安全、经济建设、社会生活中的重要程度&#xff0c;信息系统遭到破坏后对国家安全、社会秩序、公共利益以及公民、法人和其他组…

c++(类型转换+IO)[30]

类型转换 意义相近的类型------隐式类型转换 意义不想近的类型&#xff0c;值转换后有意义------显示的强制类型转换 static_cast 任何隐式类型的转换&#xff0c;非多态类型的转换&#xff08;静态转换&#xff09;&#xff0c;意义相近的转换。 用于常见的隐式类型转换&am…

Spring Boot数据访问基础知识与JDBC简单实现

目录 Spring Boot数据访问基础知识 Spring Data ORM JDBC JPA JDBC简单实现 步骤1&#xff1a;新建Maven项目&#xff0c;添加依赖 步骤2&#xff1a;配置数据源—让程序可以访问到 步骤3&#xff1a;配置数据源—让IDEA可以访问到 步骤4&#xff1a;添加数据库和表 …

今天面了一个来字节要求月薪24K,明显感觉他背了很多面试题...

最近有朋友去字节面试&#xff0c;面试前后进行了20天左右&#xff0c;包含4轮电话面试、1轮笔试、1轮主管视频面试、1轮hr视频面试。 据他所说&#xff0c;80%的人都会栽在第一轮面试&#xff0c;要不是他面试前做足准备&#xff0c;估计都坚持不完后面几轮面试。 其实&…

4.DNS和负载均衡

文章目录 coreDNS概念部署croeDNS测试 kubernetes多master集群结构master节点部署 负载均衡配置部署nginx做四层反向代理安装高可用 keepalivednginx监控脚本修改k8s中组件的配置文件 coreDNS 概念 coreDNS是kubernetes的默认DNS实现。可以为集群中的service资源创建一个资源名…

ThinkPHP6企业OA办公系统

有需要请加文章底部Q哦 可远程调试 ThinkPHP6企业OA办公系统 一 介绍 勾股OA基于ThinkPHP6开发&#xff0c;前端Layui&#xff0c;数据库mysql&#xff0c;是一款实用的企业办公系统。可多角色登录&#xff0c;集成了系统设置、人事管理、消息管理、审批管理、日常办公、客户…

构建器/建造者/构建者模式(C++)

定义 将一个复杂对象的构建与其表示相分离,使得同样的构建过程(稳定)可以创建不同的表示(变化)。 应用场景 在软件系统中&#xff0c;有时候面临着“一个复杂对象”的创建工作&#xff0c;其通常由各个部分的子对象用一定的算法构成;由于需求的变化&#xff0c;这个复杂对象…

Homer:一个简单的静态主页

什么是 Homer ? Homer 是一个完全静态的 html/js 仪表板&#xff0c;基于一个简单的 yaml 配置文件。它旨在由 HTTP 服务器提供服务&#xff0c;如果您直接通过 file:// 协议打开 index.html&#xff0c;它将无法工作。 安装 在群晖上以 Docker 方式安装。 在注册表中搜索 h…

RISC-V基础之函数调用(四)非叶函数调用(包含实例)

叶函数是指不调用其他函数&#xff0c;也不改变任何非易失性寄存器的函数2。叶函数通常是一些简单的操作&#xff0c;如数学运算或逻辑判断。叶函数的特点是可以通过模拟返回来展开&#xff0c;即不需要保存或恢复寄存器的状态。 非叶函数是指调用其他函数或改变非易失性寄存器…

百度智能云“千帆大模型平台”升级:大模型最多,Prompt模板最全

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

Rust 原生支持龙架构指令集

导读近日&#xff0c;Rust 开源社区发布 1.71.0 版本&#xff0c;实现对龙架构&#xff08;LoongArch&#xff09;指令集的原生支持。 龙架构操作系统发行版和开发者可基于上游社区源代码构建或直接下载 Rust 开源社区发布的龙架构二进制版本。Rust 开发者将在龙架构平台上获得…