各位用户为了找寻关于MySQL查询截取的深入分析的资料费劲了很多周折。这里教程网为您整理了关于MySQL查询截取的深入分析的相关资料,仅供查阅,以下为您介绍关于MySQL查询截取的深入分析的详细内容
目录
一、查询优化 1,mysql的调优大纲 2,小表驱动大表 3,in和exists 4,orderby创建表 5,groupby优化 二、慢查询日志 1,慢查询日志是什么? 2,慢查询日志的开启 3,日志分析命令mysqldumpslow 三、批量写数据脚本 1,建表 4,创建存储过程 5,调用存储过程生成数据 四、show profiles 1,介绍 3,使用show profiles 五、全局查询日志 总结
一、查询优化
1,mysql的调优大纲
慢查询的开启并捕获 explain+慢SQL分析 show profile查询SQL在Mysql服务器里面的执行细节和生命周期情况 SQL数据库服务器的参数调优
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的使用
EXISTS 语法:EXISTS(subquery) 只返回TRUE或FALSE,因此子查询中的SELECT *也可以是SELECT 1或其他,官方说法是实际执行时会忽略SELECT清单,因此没有区别 SELECT ... FROM table WHERE EXISTS(subquery) 该语法可以理解为:将查询的数据,放到子查询中做条件验证,根据验证结果(TRUE或FALSE)来决定主查询的数据结果是否得以保留。 EXISTS子查询的实际执行过程可能经过了优化而不是我们理解上的逐条对比,如果担忧效率问题,可进行实际检验以确定是否有效率问题。 EXISTS子查询往往也可以用条件表达式、其他子查询或者JOIN来替代,何种最优需要具体问题具体分析 ? 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 11create
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);
orderby命中索引的情况
orderby未命中索引的情况
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
by
时
select
*是一个大忌,只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,慢查询日志是什么?
MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中。 long_query_time的默认值为10,意思是运行10秒以上的SQL语句会被记录下来 由他来查看哪些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 ;
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%'
;
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)查看当前系统中存在的慢查询日志条数
? 1show
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 19CREATE
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;
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 7delimiter $$
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 12delimiter $$
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 12delimiter $$
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,介绍
show profile是mysql提供可以用来分析当前会话中语句执行的资源消耗情况。可以用于SQL的调优测量。 默认情况下,参数处于关闭状态,并保存最近15次的运行结果2,开启
? 1 2 3 4#查看 Show Profile 是否开启
show variables
like
‘profiling%';
#开启 Show Profile
set
profiling=
on
;
3,使用show profiles
创建测试数据
? 1 2 3 4 5 6select
*
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
执行 show profile cpu, block io for query Query_ID;
检索参数
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:把内存中临时表复制到磁盘,危险!!! locked:锁表
五、全局查询日志
切莫在生产环境配置启用
在my.cnf中配置
? 1 2 3 4 5 6# 开启
general_log=1
# 记录日志文件的路径
general_log_file=
/path/logfile
# 输出格式
log_output=FILE
编码启用
? 1 2set
global
general_log=1;
set
global
log_output=
'TABLE'
;
配置完成之后,将会记录到mysql库里的general_log表
? 1select
*
from
mysql.general_log;
总结
到此这篇关于MySQL查询截取的文章就介绍到这了,更多相关MySQL查询截取内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
原文链接:https://www.cnblogs.com/bbgs-xc/p/14293709.html