【Mysql 学习笔记】 高级优化 --- 查询截取分析


一、查询优化

在这里插入图片描述

(1) 永远小表驱动大表 (类似嵌套循环Nested Loop)

在这里插入图片描述

/*
 *   以下两种情况,执行结果是一样的,都是循环5000次
 *   但是对于mysql来说,情况一是要优于情况二的,频繁的进行io操作会消耗大量的性能
 */
 
// 情况一:可以看作与数据库建立5次连接,每次执行1000条
for(int i = 0; i < 5; i ++)
    for(int j = 0; j < 1000; j++)

// 情况二:可以看作与数据库建立1000次连接,每次执行5条
for(int i = 0; i < 1000; i ++)
    for(int j = 0; j < 5; j++)

EXISTS

  • 语法SELECT....FROM tab WHERE EXISTS(subquery);
  • 该语法可以理解为:将主查询的数据放到子查询中做条件验证,根据验证结果(true或是false)来决定主查询的数据结果是否得以保留

提示

  • EXISTS(subquery)子查询 只返回true或者false,因此 子查询中的SELECT *可以是 SELECT 1 OR SELECT X,它们并没有区别

  • EXISTS(subquery)子查询的 实际执行过程可能经过了优化 而不是我们理解上的逐条对比,如果担心效率问题,可进行实际检验以确定是否有效率问题。

  • EXISTS(subquery)子查询往往也可以用 条件表达式其他子查询 或者 JOIN替代,何种最优需要 具体问题具体分析

(2) order by 关键字优化

MySQL支持两种方式的排序,FileSortIndexIndex效率高。
它指MySQL扫描索引本身完成排序。FileSort方式效率较低


ORDER BY 满足两情况,会 使用Index方式排序

  • ORDER BY语句使用索引最左前列
  • 使用where子句与OrderBy子句条件列组合满足索引最左前列
① ORDER BY子句,尽量 使用Index方式排序,避免使用FileSort方式排序

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


② 尽可能在索引列上完成排序操作,遵照索引建的最佳左前缀

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


③ 如果不在索引列上,filesort有两种算法:mysql就要启动双路排序和单路排序

- 双路排序

MySQL4.1之前是使用双路排序,字面意思是两次扫描磁盘,最终得到数据。读取 行指针orderby列 ,对他们 进行排序,然后 扫描已经排序好的列表按照列表中的值重新从列表中读取对应的数据传输

磁盘排序字段,在 buffer进行排序,再 从磁盘取其他字段

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

- 单路排序

从磁盘读取查询需要的所有列按照orderby列buffer 对它们 进行排序,然后扫描排序后的列表进行输出,它的效率更快一些,避免了第二次读取数据,并且 把随机IO变成顺序IO,但是它 会使用更多的空间
因为它 把每一行都保存在内存中 了。

- 结论及引申出来的问题

由于 单路 是后出来的,总体而言好过双路


但是用 单路有问题
在这里插入图片描述


④ 优化策略

增大sort_buffer_size参数的设置

增大max_length_for_sort_data参数的设置

在这里插入图片描述


⑤ 小总结

MySQL两种排序方式文件排序 Using filesort扫描有序索引排序 Index

MySQL 能为排序与查询使用相同的索引创建的索引可以用于排序可以用于查询。( 比如:where age = 20 order by age )


(3) group by 关键字优化

  • groupby实质是 先排序后进行分组遵照 索引建的 最佳左前缀

  • 无法使用索引列增大max_length_for_sort_data 参数的设置+ 增大sort_buffer_size 参数的设置

  • where高于having,能写在where限定的条件就不要去having限定了。

在这里插入图片描述


二、慢日志查询

(1) 介绍

MySQL的慢查询日志是MySQL提供的一种日志记录,它 用来记录在MySQL中响应时间超过阈值的语句,具体 指运行时间超过 long_query_time 值的SQL,则会被 记录到慢查询日志 中。

long_query_time 的默认值为10,意思是 运行10秒以上的语句

慢日志查询查看哪些SQL超出了我们的最大忍耐时间值,比如一条SQL执行超过5秒钟,我们就算慢SQL,希望能收集超过5秒钟的SQL,结合之前explain进行全面分析


(2) 使用

① 说明

在这里插入图片描述


② 查看是否开启及如何开启
  • 查看
SHOW VARIABLES LIKE '%slow_query_log%'

在这里插入图片描述

  • 开启
set global slow_query_log = 1

在这里插入图片描述


③ 那么开启慢查询日志后,什么样的SQL参会记录到慢查询里面?

在这里插入图片描述


④ Case
1.查看当前多少秒算慢
SHOW VARIABLES LIKE 'long_query_time%';

在这里插入图片描述


2.设置慢的阙值时间为3s
set global long_query_time = 3; 

在这里插入图片描述


3.为什么设置后看不出变化?

在这里插入图片描述

在这里插入图片描述


4.记录慢SQL并后续分析

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


5.查询当前系统中有多少条慢查询记录

在这里插入图片描述


⑤ 配置版

在这里插入图片描述


(3) 日志分析工具 mysqldumpshow

① 介绍

日志分析工具 mysqldumpslow:在生产环境中,如果要手工分析日志,查找、分析SQL,显然是个体力活,MySQL提供了日志分析工具mysqldumpslow。


② 查看 mysqldumpslow 的帮助信息

命令mysqldumpslow --help

  • s:是表示按何种方式排序
  • c:访问次数
  • l:锁定时间
  • r:返回记录
  • t:查询时间
  • al:平均锁定时间
  • ar:平均返回记录数
  • at:平均查询时间
  • t:即为返回前面多少条的数据
  • g:后边搭配一个正则匹配模式,大小写不敏感的

③ 常用参考
# 得到返回记录集最多的10个SQL
mysqldumpslow -s r -t 10 /var/lib/mysql/slow.log
# 得到访问次数最多的10个SQL
mysqldumpslow -s c -t 10 /var/lib/mysql/slow.log
# 得到按照时间排序的前10条里面含有左连接的查询语句
mysqldumpslow -s t -t 10 -g "left join" /var/lib/mysql/slow.log
# 另外建议使用这些命令时结合|和more使用,否则出现爆屏的情况
mysqldumpslow -s r -t 10 /var/lib/mysql/slow.log | more

三、批量数据脚本

① 建表
CREATE TABLE emp(
	id int unsigned primary key auto_increment,
	empno mediumint unsigned not null default 0,
	ename varchar(20) not null default "",
	job varchar(9) not null default "",
	mgr mediumint unsigned not null default 0,
	hiredate date not null,
	sal decimal(7,2) not null,
	comm decimal(7,2) not null,
	deptno mediumint unsigned not null default 0
)ENGINE=INNODB DEFAULT CHARSET=utf8;

CREATE TABLE dept(
	deptno int unsigned primary key auto_increment,
	dname varchar(20) not null default "",
	loc varchar(8) not null default ""
)

在这里插入图片描述


② 设置参数 log_trust_function_createors

由于开启过慢查询日志,开启了 bin-log,我们就 必须为function指定一个参数,否则使用函数会报错。

  • 查看:SHOW VARIABLES LIKE 'log_bin_trust_function_creators';
  • 设置:SET GLOBAL log_bin_trust_function_creators=1;

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


③ 创建函数保证每条数据都不同
# 随机产生字符串
DELIMITER $$
CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255)
BEGIN
    DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwsyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    DECLARE return_str VARCHAR(255) DEFAULT '';
    DECLARE i INT DEFAULT 0;
    WHILE i < n DO
    SET return_str = CONCAT(return_str,SUBSTRING(chars_str,FLOOR(1+RAND()*52),1));
    SET i = i + 1;
    END WHILE;
    RETURN return_str;
END $$

# 随机产生部门编号
DELIMITER $$
CREATE FUNCTION rand_num() RETURNS INT(5)
BEGIN
    DECLARE i INT DEFAULT 0;
    SET i = FLOOR(100 + RAND() * 10);
    RETURN i;
END $$

在这里插入图片描述


④ 创建存储过程
# 向dept表批量插入
DELIMITER $$
CREATE PROCEDURE insert_dept(IN START INT(10),IN max_num INT(10))
BEGIN
DECLARE i INT DEFAULT 0;
    SET autocommit = 0;
    REPEAT
    SET i = i + 1;
    INSERT INTO dept(deptno,dname,loc) VALUES((START + i),rand_string(10),rand_string(8));
    UNTIL i = max_num
    END REPEAT;
    COMMIT;
END $$

# 向emp表批量插入
DELIMITER $$
CREATE PROCEDURE insert_emp(IN START INT(10),IN max_num INT(10))
BEGIN
DECLARE i INT DEFAULT 0;
    SET autocommit = 0;
    REPEAT
    SET i = i + 1;
    INSERT INTO emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES((START + i),rand_string(6),'SALESMAN',0001,CURDATE(),2000,400,rand_num());
    UNTIL i = max_num
    END REPEAT;
    COMMIT;
END $$

在这里插入图片描述


⑤ 调用存储过程
# 调用存储过程向dept表插入10个部门。
DELIMITER ;
CALL insert_dept(100,10);

# 调用存储过程向emp表插入50万条数据。
DELIMITER ;
CALL insert_emp(100001,500000);

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


四、Show profiles

(1) 介绍

是mysql提供可以 用来分析当前会话中语句执行的资源消耗情况可以用于SQL的调优测量

默认情况下,参数处于关闭状态,并保存最近15次的运行结果


(2) 分析步骤

① 查看和开启 show profiles
查看:SHOW VARIABLES LIKE 'profiling';

开启:SET profiling=ON;

在这里插入图片描述


② 运行SQL
select * from emp group by id%10 limit 150000;

select * from emp group by id%20 order by 5;

在这里插入图片描述


③ 查看结果,show profiles;
SHOW PROFILES;

在这里插入图片描述


④ 诊断SQL,
语法:show profile cpu,block io for query 上一步前面的问题SQL 数字号码;

例如:SHOW PROFILE cpu,block io FOR QUERY 3;

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


⑤ 日常开发需要注意的结论

converting HEAP to MyISAM 查询结果太大,内存都不够用了往磁盘上搬了。

Creating tmp table 创建临时表 (拷贝数据到临时表,用完再删除),耗费性能

Copying to tmp table on disk 把内存中临时表复制到磁盘,危险!!!

locked 死锁


五、全局查询日志 (了解)

永远不要在 生产环境 开启这个功能。

(1) 配置启用

在这里插入图片描述


(2) 编码启用

在这里插入图片描述


猜你喜欢

转载自blog.csdn.net/weixin_45260385/article/details/114840708