本文共 7075 字,大约阅读时间需要 23 分钟。
优化原则:小表驱动大表,即小的数据集驱动大的数据集。
select * from A where id in (select id from B)等价于:for select id from Bfor select * from A where A.id = B.id
当 B 表的数据集必须小于 A 表的数据集时,用 in 优于 exists。
select * from A where exists (select 1 from B where B.id = A.id)等价于:for select * from Afor select * from B where B.id = A.id
当 A 表的数据集小于 B 表的数据集时,用 exists 优先于 in。
select … from table where exists(subquery)
该语法可以理解为:将主查询的数据,放到子查询中做条件验证,根据验证结果(true 或 false)来决定主查询的数据结果是否得以保留。
MySQL 支持两种方式对的排序, FileSort 和 index,index 效率高,它指 MySQL 扫描索引本身完成排序。FileSort 方式效率较低。
Order by 满足两种情况,会使用 Index 方式排序
Order by 语句使用索引最左前列
使用 Where 字句与 Order By 字句条件列组合满足索引最左前列双路排序
取一批数据,要对磁盘进行两次扫描,众所周知,I\O是很耗时的,所以在 mysql4.1 之后,出现了第二种改进的算法,就是单路排序。
单路排序
增大 sort_buffer_size 参数的设置
增大 max_length_for_sort_data 参数的设置group by 实质是先排序后进行分组,遵照索引建的最佳左前缀
当无法使用索引列,增加 max_length_for_sort_data 参数的设置 + 增大 sort_buffer_size 参数的设置
where 高于 having,能写在 where 限定的条件就不要去 having 限定了。
MySQL 的慢查询日志是 MySQL 提供的一种日志记录,它用来记录在 MySQL 中相应时间超过阈值的语句,具体指运行时间超过 long_query_time 值得 SQL,则会被记录到慢查询日志中。
具体指运行时间超过 long_query_time 值得 SQL,则会被记录到慢查询日志中。long_query_time 得默认值为 10,意思是运行 10 秒以上的语句。
由它来查看哪些 SQL 超过了我们得最大忍耐时间值,比如一条 SQL 执行超过5秒钟,我们就算它是慢 SQL,希望能收集超过5秒得SQL,结合 explain 进行全面分析。
默认情况下,MySQL 数据库没有开启慢查询日志,需要我们手动来设置这个参数。
当然,如果不是调优需要得话,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定的性能影响。慢查询日志支持将日志记录写入文件。默认:show variables like '%slow_query_log%';
set global slow_query_log = 1;
如何永久生效,修改配置文件 my.cnf 即可(不建议长期开启)
修改 my.cnf 文件,【mysqld】下增加或修改参数
slow_query_log 和 slow_query_log_file 后,然后重启MySQL服务器即可。具体的配置参数如下:
slow_query_log=1slow_query_log_file=/var/lib/mysql/mysql-slow.log
关于慢查询得参数 slow_query_log_file,它指定慢查询日志文件得存放路径,系统默认会给一个缺省的文件 host_name-slow.log(如果没有指定参数 slow_query_log_file的话)
这个是由参数 long_query_time 控制,默认情况下 long_query_time 的值为 10 秒。
命令:show variables like 'long_query_time%';
可以使用命令修改,也可以在 my.cnf 参数里面修改。
假如运行时间正好等于 long_query_time 的情况,并不会被记录下来,也就是说:在 mysql 源码里是判断大于 long_query_time,而非大于等于
。 show variables like 'long_query_time%';
set global long_query_time=3;
需要重新连接或新开一个会话才能看到修改值。
show variables like 'long_query_time%;
show global variables like 'long_query_time';
show global status like '%Slow_queries%%';
【mysqld】下配置:slow_query_log==1;slow_query_log_file=/var/lib/mysql/atguigu-slow.loglong_query_time=3;log_output=FILE
在生产环境中,如果要手工分析日志,查找、分析SQL,MySQL提供了日志分析工具 mysqldumpslow。
查看 mysqldumpslow 的帮助指令:mysqldumpslow --help
,各个参数的意义如下:
常见例子:
// 得到返回记录集最多的 10 个SQLmysqldumpslow -s r -t 10 /var/lib/mysql/atguigu-slow.log// 得到访问次数最多的 10 个SQLmysqldumpslow -s c -t 10 /var/lib/mysql/atguigu-slow.log// 得到按照时间排序的前 10 条里面含有左连接的查询语句mysqldumpslow -s t -t -g "left join" /var/lib/mysql/atguigu-slow.log// 另外建立在使用这些命令时结合 | 和 more 使用,否则有可能出现爆屏情况mysqldumpslow -s r -t 10 /var/lib/mysql/atguigu-slow.log | more
例如往表中插入 1000W 条数据。
# 新建库create database bigData;use bigData;# 建部门表 deptcreate table dept(id int unsigned primary key auto_increment,deptno mediumint unsigned not null default 0,dname varchar(20) not null default "",loc varchar(13) not null default "")engine=innodb default charset=GBK;# 建员工表 empcreate 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=gbk;
创建函数,假如报错:This function has none of deterministic…
# 由于开启过慢查询日志,因为我们开启了 bin-log,我们就必须为我们的 function 指定一个参数。show variables like 'log_bin_trust_function_creators';set global log_bin_trust_function_creators=1;# 这样添加了参数以后,如果 mysqld 重启,上述参数又会消失,永久方法:windows:my.ini文件[mysqld]加上log_bin_trust_function_creators=1linux:/etc/my.cnf下my.cnf文件[mysqld]加上log_bin_trust_function_creators=1
DELIMITER $$ CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255) BEGIN DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghigklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'; 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 $$# 假如要删除此函数# drop function rand_string;
DELIMITER $$ CREATE FUNCTION rand_num()RETURNS INT(5)BEGIN DECLARE i INT DEFAULT 0; SET i = FLOOR(100+RAND()*10); RETURN i;END $$# 假如要删除此函数# drop function rand_num;
# 执行存储过程,往 emp 表中添加随机数据DELIMITER $$CREATE PROCEDURE insert_emp(IN START INT(10), IN max_num INT(10))BEGIN DECLARE i INT DEFAULT 0; # set autocommit = 0 把 autocommit 设置为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 表中添加随机数据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 $$
DELIMITER ;CALL insert_dept(100,10);
DELIMITER ;CALL insert_emp(100001,500000);
Show Profile 是 mysql 提供可以用来分析当前会话中语句执行的资源消耗情况。可以用于 SQL 的调优的测量
官网:
默认情况下,参数处于关闭状态,并保存最近 15 次的运行结果
Show variables like 'profiling';
set profiling=on;
show profiles;
show profile cpu,block io for query 上一步前面的问题 SQL 数字号码;
参数备注:
type: | ALL --显示所有的开销信息 | BLOCK IO --显示块IO相关开销 | CONTEXT SWITCHES --上下文切换相关开销 | CPU --显示CPU相关开销信息 | IPC --显示发送和接收相关开销信息 | MEMORY --显示内存相关开销信息 | PAGE FAULTS --显示页面错误相关开销信息 | SOURCE --显示和 Source_function,Source_file,Source_line 相关的开销信息 | SWAPS --显示交换次数相关开销的信息converting HEAP to MyISAM 查询结果太大,内存都不够用了往磁盘上搬了。
Creating tmp table 创建临时表:拷贝数据到临时表;用完再删除。
Copying to tmp table on disk 把内存中临时表复制到磁盘,危险!!!
locked
千万不要在生产环境开启这个功能。
在 mysql 的 my.cnf 中,配置如下:# 开启general_log=1# 记录日志文件的路径general_log_file=/path/logfile# 输出格式log_output=FILE
set global general_log=1;set global log_output='TABLE';// 此命令用于查看你编写的 sql 语句select * from mysql.general_log;
永远不要在生产环境开启这个功能。
转载地址:http://hpqwi.baihongyu.com/