zoukankan      html  css  js  c++  java
  • 关于mysql的查询优化

    由于工作原因,最近甲方客户那边多次反应了他们那边的系统查询速度慢,经过排除之后,发现他们那边的数据库完全没有用到索引,简直坑得一笔,通过慢查询日志分析,为数据表建立了适当的索引之后,查询速度明显的提高上来了,所以这次也总结一下如果进行mysql的优化查询。

    1.慢查询

    mysql自身是有一个慢查询时间和慢查询记录的,但是在默认情况下,我们的mysql不会记录慢查询,需要在启动mysql时候,指定记录慢查询才可以

    (1)使用show variables like 'long_query_time'命令,查看慢查询时间

    现在慢查询时间是10s,但是我们可以通过set long_query_time对其进行临时修改(关闭掉这次会话之后慢查询时间会被重置回10)

    另外,我们也可以通过show variables like '%slow%'这个命令来查看慢查询的配置

    慢查询日志默认是不启用的,所以我们要打开它,有两种方法,一种是用set重新设置变量,另一种就是直接修改配置文件,这里建议用修改变量的方法(因为是临时的)

    想要测试是否开启慢查询,可以使用select sleep(3),运行之后去对应的目录找到慢查询日志是否有记录就可以了,这里就不再多说了。

    2.构建大数据量进行测试

    因为之前优化的查询里面存储着客户的数据,这里不方便用于展示,所以我们可以自己来构建一个大数据的表,这里就用到了mysql的存储过程(使用存储过程无非就是想要插入数据运行的时间减少而已,其实我们可以通过php写代码批量插入)

    存储过程怎样写我就不多说了,而且网上也能找到大量的测试数据代码,所以这里我就直接上代码了

    (1)创建表

    CREATE TABLE dept(

    deptno MEDIUMINT   UNSIGNED  NOT NULL  DEFAULT 0 COMMENT '编号', 

    dname VARCHAR(20)  NOT NULL  DEFAULT "" COMMENT '名称',

    loc VARCHAR(13) NOT NULL DEFAULT "" COMMENT '地点'

    ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;

    CREATE TABLE emp (

    empno  MEDIUMINT UNSIGNED  NOT NULL  DEFAULT 0 COMMENT '编号',

    ename VARCHAR(20) NOT NULL DEFAULT "" COMMENT '名字',

    job VARCHAR(9) NOT NULL DEFAULT "" COMMENT '工作',

    mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '上级编号',

    hiredate DATE NOT NULL COMMENT '入职时间',

    sal DECIMAL(7,2)  NOT NULL COMMENT '薪水',

    comm DECIMAL(7,2) NOT NULL COMMENT '红利',

    deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '部门编号'

    )ENGINE=MyISAM DEFAULT CHARSET=utf8 ;

    分别是部门表(dept)和员工表(emp),这里我是故意没有创建主键,等下留作演示用

    (2)创建自定义函数

    delimiter $$

    创建一个自定义函数,目的是返回1-10的随机数

    create function rand_num()
    returns int
    begin
      return floor(1+rand()*10);
    end$$

    创建一个自定义函数,目的是返回随机字符串

    create function rand_string(n INT) returns varchar(255) begin  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$$

    为了能使存储过程正常执行,要先把mysql的语句结束符号修改成$$,创建完后用delimiter命令改回;就可以了

    (3)创建插入数据的存储过程

    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 values ((start+i) ,rand_string(6),'SALESMAN',0001,curdate(),2000,400,rand_num());
      until i = max_num
     end repeat;
       commit;
     end $$

    (4)调用call insert_emp(100001,4000000)创建400w条数据

    插入400w条数据用了8分半钟,这时我们可以去看下慢查询日志是否记录了

    3.查询优化

    首先,我们在没有索引的情况下,对员工表进行查询

    查找员工号为300w的数据,用时32.11s,这估计是谁都不能忍的事,要是被老板发现了,估计就要直接掀桌了,所以我们就用explain工具来分析一下这条查询

    那么,现在我们为员工编号加上主键索引,结果又会如何呢

    只用了0.03秒,查询效率提高了1000倍以上!

    现在我们来分析一下这个查询语句吧

    那么,现在我们来试试多表查询的情况,先向部门表插入几条数据,这里就不再多说了

    可以发现,用了51s才查询完毕(因为数据过多,所以用ctrl+c中断输出,这里补充上查询语句select * from dept left join emp on dept.deptno=emp.deptno where dept.deptno=1;)

    用explain分析可以看出两个表都是全表扫描

    为emp表加上deptno的索引后,查询结果和分析结果如下

    只用了7.34s,而且查询数量明显相比第一次只查询了不到40w条,查询效率提高了7倍以上

    然而我们也发现了,dept表仍然没有用到索引,所以我们试试看为dept表加上主键索引

    虽然有所优化,但是并不明显,其实上述实验结果也可以看出,总查询条数(rows)/总数据量的比值越小,索引优化查询的效果越明显

    mysql的查询优化就暂时先介绍到这里了,想要具体的对mysql进行优化,其实还需要explain各参数的详解和使用索引的注意事项等,这些我会以后再个博客进行详细的介绍的

    ,这里就先挖个坑吧

    explain详解:(待补充)

    mysql使用索引的注意事项:(待补充)

  • 相关阅读:
    CSP2018-09
    CSP2018-03
    CSP2017-12
    CSP2017-09
    CSP2017-03
    CSP2016-12
    [算法设计与分析] 奶酪 (并查集)
    5555
    阿超
    结对作业
  • 原文地址:https://www.cnblogs.com/zhp-king/p/6936956.html
Copyright © 2011-2022 走看看