一、 发现慢查询
如何从一个大项目中,迅速的定位执行速度慢的语句,这是本章节将要解决的问题。
1. 慢查询的定义
怎样的查询才算是慢查询,有没有一个量化的标准呢?
慢查询定义
慢查询是指执行时间超过慢查询时间的sql语句。
查看慢查询时间的方法
show variables like 'long_query_time';
可以显示当前慢查询时间。MySql默认慢查询时间为10秒
可以通过如下语句对慢查询的定义进行修改
set global long_query_time=1;
(如果你的mysql设置了缓存,那么需要重新进入命令行窗口才会查出变化)
需要注意的是,这个语句特意在变量前加上了global,表明这次的设置是对整个Mysql有效的,而默认情况下变量前的修饰符是session(会话),也就是只对当前窗口有效。
这一讲只是开个头,下一讲,我们会为慢查询的发生准备数据,即创建一张大表。
2. 慢查询数据准备
要想发现慢查询,首先要使慢查询发生。在一张普通数量级的表格中是不能发生慢查询的,除非你对于慢查询的定义时一个毫秒。因此我们必须手动创建一张大数量级的表,这里选择创建一张40万数量级的表(同学们也可以创建百万级的,如果你们的电脑很厉害。但是一般情况下,十万级的数据就可以看出慢查询了)。
1) 创建数据库
Create database bigTable default character set GBK;
2) 创建表
部门表
CREATE 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 ;
雇员表
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=GBK ;
3) 创建函数
函数用于随机产生数据,保证每条数据都不同
函数1 创建#
创建函数. 用于随机产生字符串。该函数接收一个整数
delimiter $$#定义一个新的命令结束符合
create function rand_string(n INT)
returns varchar(255) #该函数会返回一个字符串
begin
#chars_str定义一个变量 chars_str,类型是 varchar(100),默认值'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
declare chars_str varchar(100) default
'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
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 $$
函数2创建
用于随机产生部门编号
create function rand_num( )
returns int(5)
begin
declare i int default 0;
set i = floor(10+rand()*500);
return i;
end $$
4) 创建存储过程
存储过程一#
该存储过程用于往emp表中插入大量数据
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 $$
执行存储过程,往emp表添加40万条数据
call insert_emp(100001,400000);
查询,发现Emp表插入了40万条记录
存储过程二#
往dept表添加随机数据
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);
3. 记录慢查询
此时我们已经有让慢查询发生的成本了。执行以下语句,你就知道什么叫慢!查!询!
select empno from emp where ename='';
一个很明显找不到结果的查询语句居然也执行了近3秒钟。
这时候,作为DBA就应该把这个sql语句记录下来,是记在记事本还是写在笔记本呢?不用想太多了,不用你自己记,MySQL提供了慢查询日志功能,自动帮你记录慢查询的语句。
1) 把慢查询的sql记录到日志中
首先你要打开慢查询日志文件记录器
使用
show variables like 'slow%';
你会发现默认情况下慢查询日志记录器关闭的
使用
set global slow_query_log=ON;
打开之
此时你会发现mysql安装目录下的data文件夹中出现了以你本机名命名的日志文件
此时再执行慢查询操作
打开日志文件发现出现记录
以后只需要定期检查日志文件就可以找到慢查询语句了
注意:
在找到慢查询语句后,要通过反复使用select语句确认慢查询,注意只能使用select语句,就算是原来语句为delete或者update等,也要用select代替,因为只有select不会弄脏数据库
2) 另一种发现慢查询语句的方法
要是你使用hibernate进行J2ee开发,可以使用一下方式。
在页面中进行操作,当发现某个操作的响应较慢时,查看Eclipse控制台的Hibernate输出sql语句,此语句即为慢查询语句。