当前位置: 代码迷 >> SQL >> 2. SQL 话语本身的优化(慢查询)
  详细解决方案

2. SQL 话语本身的优化(慢查询)

热度:326   发布时间:2016-05-05 09:35:49.0
2. SQL 语句本身的优化(慢查询)

这里写图片描述

MySQL客户端连接成功后,通过使用show [session|global] status 命令可以提供服务器状态信息。其中的session来表示当前的连接的统计结果,global来表示自数据库上次启动至今的统计结果。默认是session级别的。下面的例子:show status like ‘Com_%’;其中Com_XXX表示XXX语句所执行的次数。重点注意:Com_select,Com_insert,Com_update,Com_delete通过这几个参数,可以容易地了解到当前数据库的应用是以插入更新为主还是以查询操作为主,以及各类的SQL大致的执行比例是多少。还有几个常用的参数便于用户了解数据库的基本情况。Connections:试图连接MySQL服务器的次数Uptime:服务器工作的时间(单位秒)Slow_queries:慢查询的次数 (默认是慢查询时间10s)

Sql语句本身的优化

如何从一个大项目中,迅速的定位执行速度慢的语句. (定位慢查询);①   首先我们了解mysql数据库的一些运行状态如何查询(比如想知道当前mysql运行的时间/一共执行了多少次select/update/delete.. / 当前连接)show status常用的:show status like ‘uptime’ ; show  stauts like ‘com_select’  show stauts like ‘com_insert’ ...类推 update  delete? show [session|global] status like .... 如果你不写  [session|global] 默认是session 会话,指取出当前窗口的执行,如果你想看所有(从mysql 启动到现在,则应该 global)show status like ‘connections’; //显示慢查询次数show status like ‘slow_queries’;

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

netstat -an 本地查看哪台机器连接

这里写图片描述


②   如何去定位慢查询构建一个大表(400 万)-> 存储过程构建默认情况下,mysql认为10秒才是一个慢查询.(4000W数据一个查询才会慢到10s),所以要修改慢查询的默认时间。 1. 修改mysql的慢查询.show variables like ‘long_query_time’ ; //可以显示当前慢查询时间set long_query_time=1 ;//可以修改慢查询时间

这里写图片描述
这里写图片描述


构建大表->大表中记录有要求, 记录是不同才有用,否则测试效果和真实的相差大.为了存储过程能够正常执行,我们需要把命令执行结束符修改#这里我创建了一个函数. #rand_string(n INT) rand_string 是函数名 (n INT) //该函数接收一个整数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 $$

这里写图片描述

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

在程序中调用函数:<?php$link = mysql_connect('localhost','root','123456');if (!$link) {    die('失败');}mysql_select_db('test3');// dual 空表,哑无表$sql = "select rand_string(6) my from dual";//真实表情况,具体字段/*$sql = "select rand_string(6) from salgrade";$sql = "select rand_string(6),grade from salgrade";*/$res = mysql_query($sql,$link);if ($row = mysql_fetch_assoc($res)){    echo $row['my'];}

这里写图片描述


#创建一个存储过程#随即添加雇员[光标]  400w#start 表示雇员的编号从哪里开始#max_num 表示一共增加多少雇员create procedure insert_emp(in start int(10),in max_num int(10))begindeclare i int default 0; #set autocommit =0 把autocommit设置成0 set autocommit = 0;   repeat set i = i + 1; insert into emp values ((start+i) ,rand_string(6),'SALESMAN',0001,curdate(),2000,400,rand_num());  until i = max_num end repeat;   commit; end $$
delimiter ;#调用刚刚写好的函数, 1800000条记录,从100001号开始call insert_emp(100001,4000000);

这里写图片描述

③   这时我们如果出现一条语句执行时间超过1秒中,就会统计到

这里写图片描述

④   如果把慢查询的sql记录到我们的一个日志中在默认情况下,我们的mysql不会记录慢查询,需要在启动mysql时候,指定记录慢查询才可以bin\mysqld.exe - -safe-mode  - -slow-query-log [mysql5.5 可以在my.ini指定]bin\mysqld.exe –log-slow-queries=d:/abc.log [低版本mysql5.0可以在my.ini指定]先关闭mysql,再启动, 如果启用了慢查询日志,默认把这个文件放在my.ini 文件中记录的位置#Path to the database rootdatadir="C:/Documents and Settings/All Users/Application Data/MySQL/MySQL Server 5.5/Data/"

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述


⑤   测试,可以看到在日志中就记录下我们的mysql慢sql语句.

这里写图片描述
这里写图片描述


#创建表DEPTCREATE TABLE dept( /*部门表*/deptno MEDIUMINT   UNSIGNED  NOT NULL  DEFAULT 0, dname VARCHAR(20)  NOT NULL  DEFAULT "",loc VARCHAR(13) NOT NULL DEFAULT "") ENGINE=MyISAM DEFAULT CHARSET=utf8 ;#创建表EMP雇员CREATE TABLE emp(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=MyISAM DEFAULT CHARSET=utf8 ;#工资级别表CREATE TABLE salgrade(grade MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,losal DECIMAL(17,2)  NOT NULL,hisal DECIMAL(17,2)  NOT NULL)ENGINE=MyISAM DEFAULT CHARSET=utf8;INSERT INTO salgrade VALUES (1,700,1200);INSERT INTO salgrade VALUES (2,1201,1400);INSERT INTO salgrade VALUES (3,1401,2000);INSERT INTO salgrade VALUES (4,2001,3000);INSERT INTO salgrade VALUES (5,3001,9999);# 随机产生字符串#定义一个新的命令结束符合delimiter $$#删除自定的函数drop  function rand_string $$#这里我创建了一个函数. #rand_string(n INT) rand_string 是函数名 (n INT) //该函数接收一个整数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 $$delimiter ;select rand_string(6);# 随机产生部门编号delimiter $$drop  function rand_num $$#这里我们又自定了一个函数create function rand_num( )returns int(5)begin  declare i int default 0; set i = floor(10+rand()*500);return i;  end $$delimiter ;select rand_num();#******************************************#向emp表中插入记录(海量的数据)delimiter $$drop procedure insert_emp $$#创建一个存储过程#随即添加雇员[光标]  400w#start 表示雇员的编号从哪里开始#max_num 表示一共增加多少雇员create procedure insert_emp(in start int(10),in max_num int(10))begindeclare i int default 0; #set autocommit =0 把autocommit设置成0 set autocommit = 0;   repeat set i = i + 1; insert into emp values ((start+i) ,rand_string(6),'SALESMAN',0001,curdate(),2000,400,rand_num());  until i = max_num end repeat;   commit; end $$delimiter ;#调用刚刚写好的函数, 1800000条记录,从100001号开始call insert_emp(100001,4000000);#**************************************************************#  向dept表中插入记录delimiter $$drop procedure insert_dept $$create procedure insert_dept(in start int(10),in max_num int(10))begindeclare i int default 0;  set autocommit = 0;   repeat set i = i + 1; insert into dept values ((start+i) ,rand_string(10),rand_string(8));  until i = max_num end repeat;   commit; end $$delimiter ;call insert_dept(100,10);#------------------------------------------------#向salgrade 表插入数据delimiter $$drop procedure insert_salgrade $$create procedure insert_salgrade(in start int(10),in max_num int(10))begindeclare i int default 0;  set autocommit = 0; ALTER TABLE emp DISABLE KEYS;   repeat set i = i + 1; insert into salgrade values ((start+i) ,(start+i),(start+i));  until i = max_num end repeat;   commit; end $$delimiter ;#测试不需要了#call insert_salgrade(10000,1000000);#----------------------------------------------
  相关解决方案