当前位置:数据库 > > 正文

mysql实验总结分析(MySQL查询截取的深入分析)

时间:2022-01-17 01:08:46类别:数据库

mysql实验总结分析

MySQL查询截取的深入分析

 

一、查询优化

 

1,mysql的调优大纲

 

2,小表驱动大表

  mysql的join实现原理是,以驱动表的数据为基础,“嵌套循环”去被驱动表匹配记录。驱动表的索引会失效,而被驱动表的索引有效。

  • ?
  • 1
  • 2
  • #假设 a表10000数据,b表20数据
  • select * from a join b on a.bid =b.id
  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • a表驱动b表为:
  • for 20条数据
  •  匹配10000数据(根据on a.bid=b.id的连接条件,进行B+树查找)
  • 查找次数为:20+ log10000
  • b表驱动a表为
  • for 10000条数据
  •  匹配20条数据(根据on a.bid=b.id的连接条件,进行B+树查找)查找次数为:10000+ log20
  •  

    3,in和exists

      exists的使用

  • ?
  • 1
  • 2
  • 3
  • 4
  • #采用in则是,内表B驱动外表A
  • select * from A where id in (select id from B)
  • #采用exists则是,外表A驱动内表B
  • select * from A where exists(select 1 from B where B.id = A.id)
  •   结论:

  • ?
  • 1
  • 2
  • 3
  • 永远记住小表驱动大表
  • 当 B 表数据集小于 A 表数据集时,使用 in
  • 当 A 表数据集小于 B 表数据集时,使用 exist
  •  

    4,orderby创建表

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • create table tblA(
  •  #id int primary key not null auto_increment,
  •  age int,
  •  birth timestamp not null
  • );
  •  
  • insert into tblA(age, birth) values(22, now());
  • insert into tblA(age, birth) values(23, now());
  • insert into tblA(age, birth) values(24, now());
  • #创建复合索引
  • create index idx_A_ageBirth on tblA(age, birth);
  • mysql实验总结分析(MySQL查询截取的深入分析)

    orderby命中索引的情况

    mysql实验总结分析(MySQL查询截取的深入分析)

    orderby未命中索引的情况

    mysql实验总结分析(MySQL查询截取的深入分析)

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • select * from user where name = "zs" order by age
  • #双路排序
  • 1)从 name 找到第一个满足 name = 'zs' 的主键id
  • 2)根据主键 id 取出整行,把排序字段 age 和主键 id 这两个字段放到 sort buffer(排序缓存) 中
  • 3)从name 取下一个满足 name = 'zs' 记录的主键 id
  • 4)重复 2、3 直到不满足 name = 'zs'
  • 5)对 sort_buffer 中的字段 age 和主键 id 按照字段 age进行排序
  • 6)遍历排序好的 id 和字段 age ,按照 id 的值回到原表中取出 所有字段的值返回给客户端
  •  
  • #单路排序
  • 1)从name找到第一个满足 name ='zs' 条件的主键 id
  • 2)根据主键 id 取出整行,取出所有字段的值,存入 sort_buffer(排序缓存)中
  • 3)从索引name找到下一个满足 name = 'zs' 条件的主键 id
  • 4)重复步骤 2、3 直到不满足 name = 'zs'
  • 5)对 sort_buffer 中的数据按照字段 age 进行排序,返回结果给客户端
  • 单路排序的问题及优化

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 问题:
  •  由于单路是改进的算法,总体而言好过双路
  •  在sort_buffer中,方法B比方法A要多占用很多空间,因为方法B是把所有字段都取出,所以有可能取出的数据的总大小超出了sort_buffer的容量,导致每次只能取sort_buffer容量大小的数据,进行排序(创建tmp文件,多路合并),排完再取取sort_buffer容量大小,再排…… 从而会导致多次I/O。
  • 优化策略:
  •  增大sort_buffer_size参数的设置
  •  增大max_length_for_sort_data参数的设置
  • 注意事项:
  •   Order byselect *是一个大忌,只Query需要的字段。因为字段越多在内存中存储的数据也就也多,这样就导致每次I/O能加载的数据列越少。
  •  

    5,groupby优化

    1)group by实质是先排序后进行分组,遵照索引的最佳左前缀
    2)当无法使用索引列,增大max_length_for_sort_data参数的设置+增大sort_buffer_size参数的设置
    3)where高于having,能写在where限定的条件就不要去having限定了
    4)其余的规则均和 order by 一致

     

    二、慢查询日志

     

    1,慢查询日志是什么?

    1. MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中。
    2. long_query_time的默认值为10,意思是运行10秒以上的SQL语句会被记录下来
    3. 由他来查看哪些SQL超出了我们的最大忍耐时间值,比如一条sql执行超过5秒钟,我们就算慢SQL,希望能收集超过5秒的sql,结合之前explain进行全面分析。

     

    2,慢查询日志的开启

      默认情况下,MySQL的慢查询日志是没有开启的。如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会影响到性能,慢查询日志支持将日志记录写入文件。

    a)开启慢查询日志

  • ?
  • 1
  • 2
  • 3
  • 4
  • #查看是否开启慢日志
  • show variables like 'slow_query_log%';
  • #开启慢查询日志,想要永久有效在my.cnf中设置
  • set global slow_query_log = 1 ;
  • mysql实验总结分析(MySQL查询截取的深入分析)

    b)设置慢查询日志的阈值

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • #查看慢查询日志的阈值时间 默认为10s
  • show variables like 'long_query_time%';
  • #设置为3s 重启失效,想要永久有效在my.cnf中设置
  • set global long_query_time = 3
  • #再次查看,需要切换窗口查看
  • show variables like 'long_query_time%';
  • mysql实验总结分析(MySQL查询截取的深入分析)

    c)持久化慢查询日志和时间阈值

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • [mysqld]
  • #持久化慢查询日志
  • slow_query_log=1;
  • slow_query_log_file=/var/lib/mysql/hadoop102-slow.log
  • long_query_time=3;
  • log_output=FILE
  • d)慢查询案例

  • ?
  • 1
  • 2
  • #查询等待4s
  • select sleep(4);
  • ?
  • 1
  • 2
  • #在linux系统中,查看慢查询日志
  • cat /var/lib/mysql/hadoop102-slow.log
  • e)查看当前系统中存在的慢查询日志条数

  • ?
  • 1
  • show global status like '%Slow_queries%';
  •  

    3,日志分析命令mysqldumpslow

    a)参数解释

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

    b)常用方法

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • #得到返回记录集最多的10个SQL
  • mysqldumpslow -s r -t 10 /var/lib/mysql/hadoop102-slow.log
  • #得到访问次数最多的10个SQL
  • mysqldumpslow -s c -t 10 /var/lib/mysql/hadoop102-slow.log
  • #得到按照时间排序的前10条里面含有左连接的查询语句
  • mysqldumpslow -s t -t 10 -g "left join" /var/lib/mysql/hadoop102-slow.log
  • #这些命令时结合 | 和more使用
  • mysqldumpslow -s r -t 10 /var/lib/mysql/hadoop102-slow.log | more
  •  

    三、批量写数据脚本

     

    1,建表

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • CREATE TABLE dept
  • (
  •  deptno int unsigned primary key auto_increment,
  •  dname varchar(20) not null default '',
  •  loc varchar(8) not null default ''
  • )ENGINE=INNODB DEFAULT CHARSET=utf8;
  •  
  • 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;
  • 2,设置是否可以信任存储函数创建者

  • ?
  • 1
  • 2
  • 3
  • 4
  • #查看binlog状态
  • show variables like 'log_bin%';
  • #添加可以信任存储函数创建者
  • set global log_bin_trust_function_creators = 1;
  • mysql实验总结分析(MySQL查询截取的深入分析)

    3,创建函数

    随机产生字符串的函数

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • # 定义两个 $$ 表示结束 (替换原先的;)
  • delimiter $$
  • create function rand_string(n int) returns varchar(255)
  • begin
  •  declare chars_str varchar(100) default 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  •  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 $$
  • 随机产生部门编号的函数

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • delimiter $$
  • create function rand_num() returns int(5)
  • begin
  •  declare i int default 0;
  •  set i=floor(100+rand()*10);
  •  return i;
  • end $$
  •  

    4,创建存储过程

    创建往emp表中插入数据的存储过程

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 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表中插入数据的存储过程

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 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 $$
  •  

    5,调用存储过程生成数据

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • #向 部门表插入10条数据
  • DELIMITER ;
  • CALL insert_dept(100, 10);
  • #向 员工表插入50w条数据
  • CALL insert_emp(100001, 500000);
  •  

    四、show profiles

     

    1,介绍

    2,开启

  • ?
  • 1
  • 2
  • 3
  • 4
  • #查看 Show Profile 是否开启
  • show variables like ‘profiling%';
  • #开启 Show Profile
  • set profiling=on;
  •  

    3,使用show profiles

    创建测试数据

  • ?
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • select * from emp group by id%10 limit 150000;
  • select * from emp group by id%10 limit 150000;
  • select * from emp group by id%10 order by 5;
  • select * from emp
  • select * from dept
  • select * from emp left join dept on emp.deptno = dept.deptno
  • 执行show profiles

    mysql实验总结分析(MySQL查询截取的深入分析)

    执行 show profile cpu, block io for query Query_ID;

    mysql实验总结分析(MySQL查询截取的深入分析)

    检索参数

    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:创建临时表,mysql 先将拷贝数据到临时表,然后用完再将临时表删除
    Copying to tmp table on disk:把内存中临时表复制到

    标签:
    上一篇下一篇

    猜您喜欢

    热门推荐