时间:2021-07-01 10:21:17 帮助过:10人阅读
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
exists的使用
SELECT *
也可以是SELECT 1
或其他,官方说法是实际执行时会忽略SELECT清单,因此没有区别
SELECT ... FROM table WHERE EXISTS(subquery)
#采用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)
结论:
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);
MySQL4.1之前是使用双路排序,字面意思是两次扫描磁盘,最终得到数据。读取行指针和order by列,对他们进行排序,然后扫描已经排序好的列表,按照列表中的值重新从列表中读取对应的数据传输
从磁盘读取查询需要的所有列,按照order by列在buffer对它们进行排序,然后扫描排序后的列表进行输出,它的效率更快一些,避免了第二次读取数据,并且把随机IO变成顺序IO,但是它会使用更多的空间,因为它把每一行都保存在内存中了。
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 进行排序,返回结果给客户端
问题: 由于单路是改进的算法,总体而言好过双路 在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能加载的数据列越少。
1)group by实质是先排序后进行分组,遵照索引的最佳左前缀 2)当无法使用索引列,增大max_length_for_sort_data参数的设置+增大sort_buffer_size参数的设置 3)where高于having,能写在where限定的条件就不要去having限定了 4)其余的规则均和 order by 一致
默认情况下,MySQL的慢查询日志是没有开启的。如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会影响到性能,慢查询日志支持将日志记录写入文件。
#查看是否开启慢日志 show variables like ‘slow_query_log%‘; #开启慢查询日志,想要永久有效在my.cnf中设置 set global slow_query_log = 1 ;
#查看慢查询日志的阈值时间 默认为10s show variables like ‘long_query_time%‘; #设置为3s 重启失效,想要永久有效在my.cnf中设置 set global long_query_time = 3 #再次查看,需要切换窗口查看 show variables like ‘long_query_time%‘;
[mysqld] #持久化慢查询日志 slow_query_log=1; slow_query_log_file=/var/lib/mysql/hadoop102-slow.log long_query_time=3; log_output=FILE
#查询等待4s select sleep(4);
#在linux系统中,查看慢查询日志 cat /var/lib/mysql/hadoop102-slow.log
show global status like ‘%Slow_queries%‘;
-s:是表示按何种方式排序
c:访问次数
l:锁定时间
r:返回记录
t:查询时间
al:平均锁定时间
ar:平均返回记录数
at:平均查询时间
-t:即为返回前面多少条的数据
-g:后边搭配一个正则匹配模式,大小写不敏感的
#得到返回记录集最多的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
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
#查看binlog状态 show variables like ‘log_bin%‘; #添加可以信任存储函数创建者 set global log_bin_trust_function_creators = 1;
# 定义两个 $$ 表示结束 (替换原先的;) 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 $$
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 $$
#向 部门表插入10条数据 DELIMITER ; CALL insert_dept(100, 10); #向 员工表插入50w条数据 CALL insert_emp(100001, 500000);
#查看 Show Profile 是否开启 show variables like ‘profiling%’; #开启 Show Profile set profiling=on;
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
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:锁表
切莫在生产环境配置启用
# 开启 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;
MySQL查询截取分析
标签:concat 介绍 arc 子查询 ext mysqld into birt status