MySQL查询截取分析

时间:2021-01-20 12:07:20   收藏:0   阅读:0

一、查询优化

1,mysql的调优大纲

  1. 慢查询的开启并捕获
  2. explain+慢SQL分析
  3. show profile查询SQL在Mysql服务器里面的执行细节和生命周期情况
  4. SQL数据库服务器的参数调优

2,小表驱动大表

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

#假设 a表10000数据,b表20数据
select * from a join b on a.bid =b.id
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. EXISTS 语法:EXISTS(subquery) 只返回TRUE或FALSE,因此子查询中的SELECT *也可以是SELECT 1或其他,官方说法是实际执行时会忽略SELECT清单,因此没有区别
    • SELECT ... FROM table WHERE EXISTS(subquery)
    • 该语法可以理解为:将查询的数据,放到子查询中做条件验证,根据验证结果(TRUE或FALSE)来决定主查询的数据结果是否得以保留
  2. EXISTS子查询的实际执行过程可能经过了优化而不是我们理解上的逐条对比,如果担忧效率问题,可进行实际检验以确定是否有效率问题。
  3. EXISTS子查询往往也可以用条件表达式、其他子查询或者JOIN来替代,何种最优需要具体问题具体分析
#采用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. 当 B 表数据集小于 A 表数据集时,使用 in
  3. 当 A 表数据集小于 B 表数据集时,使用 exist

4,order by

创建表

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);

  技术图片

order by命中索引的情况

  技术图片

order by未命中索引的情况

  技术图片

结论:

5,group by优化

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

二、慢查询日志

1,慢查询日志是什么?

2,慢查询日志的开启

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

a)开启慢查询日志

#查看是否开启慢日志
show variables like slow_query_log%;
#开启慢查询日志,想要永久有效在my.cnf中设置
set global slow_query_log = 1 ;

  技术图片

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

#查看慢查询日志的阈值时间  默认为10s
show variables like long_query_time%;
#设置为3s 重启失效,想要永久有效在my.cnf中设置
set global long_query_time = 3
#再次查看,需要切换窗口查看
show variables like long_query_time%;

  技术图片

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

[mysqld]
#持久化慢查询日志
slow_query_log=1;
slow_query_log_file=/var/lib/mysql/hadoop102-slow.log
long_query_time=3;
log_output=FILE

d)慢查询案例

#查询等待4s
select sleep(4); 
#在linux系统中,查看慢查询日志
cat /var/lib/mysql/hadoop102-slow.log

e)查看当前系统中存在的慢查询日志条数

show global status like %Slow_queries%;

3,日志分析命令mysqldumpslow

a)参数解释

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

b)常用方法

#得到返回记录集最多的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,建表

技术图片
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;
View Code

2,设置是否可以信任存储函数创建者

#查看binlog状态
show variables like log_bin%;
#添加可以信任存储函数创建者
set global log_bin_trust_function_creators = 1;

  技术图片

3,创建函数

# 定义两个 $$ 表示结束 (替换原先的;)
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 $$
delimiter $$
create function rand_num() returns int(5)
begin
    declare i int default 0;
    set i=floor(100+rand()*10);
    return i;
end $$

4,创建存储过程

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 $$
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,调用存储过程生成数据

#向 部门表插入10条数据
DELIMITER ;
CALL insert_dept(100, 10);
#向 员工表插入50w条数据
CALL insert_emp(100001, 500000);

四、show profiles

1,介绍

2,开启

#查看 Show Profile 是否开启
show variables like ‘profiling%’;
#开启 Show Profile
set profiling=on;

3,使用show profiles

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

  技术图片

  技术图片

五、全局查询日志

  切莫在生产环境配置启用

# 开启
general_log=1
# 记录日志文件的路径
general_log_file=/path/logfile
# 输出格式
log_output=FILE
set global general_log=1;
set global log_output=TABLE;
select * from mysql.general_log;

 

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!