【Mysql优化04】查询索引优化实例

(1)查询优化

(1.1)单表查询索引(在where/order by等条件的字段列上创建复合索引,避免索引失效)

(1.1.1)建表sql
CREATE TABLE IF NOT EXISTS `article` (
`id` INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
`author_id` INT(10) UNSIGNED NOT NULL,
`category_id` INT(10) UNSIGNED NOT NULL,
`views` INT(10) UNSIGNED NOT NULL,
`comments` INT(10) UNSIGNED NOT NULL,
`title` VARBINARY(255) NOT NULL,
`content` TEXT NOT NULL
);
 
INSERT INTO `article`(`author_id`, `category_id`, `views`, `comments`, `title`, `content`) VALUES
(1, 1, 1, 1, '1', '1'),
(2, 2, 2, 2, '2', '2'),
(1, 1, 3, 3, '3', '3');
 
SELECT * FROM article;
(1.1.2)案例

(1)第一步:执行语句:

EXPLAIN SELECT id,author_id FROM article WHERE category_id = 1 AND comments > 1 ORDER BY views DESC LIMIT 1;

表示从article表中查询category_id为1且comments > 1的 id,author_id两个值,查询结果先根据浏览量views排序,排序后取前1条数据
在这里插入图片描述如果所示:
id=1表示这个select被执行的顺序使第一位
select_type=simple表示简单的select查询,不包含子查询或者union
table=article表示查询的表是article
type=ALL表示遍历全表。是最差的结果
possible_keys=null表示可能应用在这张表上的索引为空
key=null表示没有使用索引
key_len=null表示使用的索引的长度为0
ref=null表示索引的列没有被使用
rows=3表示mysql认为它执行查询时必须检查的行数
Exta=using where;using FileSort表示使用了where过滤,使用了一个外部的索引排序而不是按照表内的索引顺序进行读取。using FileSort是最坏的情况,表示没有使用索引排序,而是使用文件排序。

(2)第二步:开始优化,创建索引:

create index idx_article_ccv on article(category_id,comments,views);

1-首先查询的字段是id和author_id,
2-然后,where判断条件是category_id和comments,
3-接着,order by的条件是views。
4-于是创建了一个复合索引包含3个条件列category_id、comments、views

(3)第三步:查看一下新创建的索引:show index from article;
在这里插入图片描述表示这个复合索引的查询顺序是先category_id,然后comments,最后views

(4)第四步:第二次EXPLAIN:EXPLAIN SELECT id,author_id FROM article WHERE category_id = 1 AND comments > 1 ORDER BY views DESC LIMIT 1;
在这里插入图片描述type从 ALL:遍历全表,变成了 range:只检索到给定范围的行,用一个索引来选择行
possible_keys变成了idx_article_ccv,表示可以用的索引
key变成了idx_article_ccv,表示已用的索引
key_len变成了8,
ref=null表示索引的列没有被使用
rows变成了1,表示只检查1行
Exta=using where;using FileSort表示使用了where过滤,使用了一个外部的索引排序而不是按照表内的索引顺序进行读取。using FileSort是最坏的情况

(5)结论:
#type 变成了 range,这是可以忍受的。但是 extra 里使用 Using filesort 仍是无法接受的。
#但是我们已经建立了索引,为啥没用呢?
#这是因为按照 BTree 索引的工作原理,
#先排序 category_id,如果遇到相同的 category_id 则再排序 comments,如果遇到相同的 comments 则再排序 views。
#当 comments 字段在联合索引里处于中间位置时,因comments > 1 条件是一个范围值(所谓 range,范围后面全失效,导致views索引失效),MySQL 无法利用索引再对后面的 views 部分进行检索,即 range 类型查询字段后面的索引无效。

(6)第五步:删除第一次加的索引:DROP INDEX idx_article_ccv ON article;

(7)第六步:第二次创建索引:create index idx_article_cv on article(category_id,views);
去掉范围检索条件的索引,避免索引失效,在category_id和views两个列上创建索引,这下这两个索引就不会失效了

(8)第七步:第三次EXPLAIN:EXPLAIN SELECT id,author_id FROM article WHERE category_id = 1 AND comments > 1 ORDER BY views DESC LIMIT 1;
在这里插入图片描述结论:可以看到,type 变为了 ref非唯一性索引扫描,Extra 中的 Using filesort 也消失了,结果非常理想。

(1.2)关联(两表)查询优化(在被驱动表上创建索引才有效,left join时右表是被驱动表,inner join时大表是被驱动表)

(1.2.1)建表sql
CREATE TABLE IF NOT EXISTS `class` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`card` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE IF NOT EXISTS `book` (
`bookid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`card` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`bookid`)
);
 
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO class(card) VALUES(FLOOR(1 + (RAND() * 20)));
 
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));
INSERT INTO book(card) VALUES(FLOOR(1 + (RAND() * 20)));

(1.2.2)left join案例(跟在from后面的表为被驱动表(大表);跟在leftjoin后面的表为驱动表(小表))

(1)第一步:第一次EXPLAIN:EXPLAIN SELECT * FROM class LEFT JOIN book ON class.card = book.card;
表示class表左连接book表,连接条件是class.card = book.card,book是左表,class是右表,book表的值全显示,class表的值只显示满足条件的,不满足的显示为null

在这里插入图片描述注意:type=ALL全检索

(2)第二步:添加左表book索引
在连接条件字段card上创建一个索引

ALTER TABLE `book` ADD INDEX Y (`card`);

(3)第三步:第二次EXPLAIN:

EXPLAIN SELECT * FROM class LEFT JOIN book ON class.card = book.card;

在这里插入图片描述#可以看到第二行的左表book的 type 变为了 ref,rows 也变成了优化比较明显。
#这是由左连接特性决定的。LEFT JOIN 条件用于确定如何从右表搜索行,左边一定都有,
#所以右边class表是我们的关键点,一定需要建立索引。

(4)第四步:删除旧索引:DROP INDEX Y ON book;

(5)第五步:给右表card添加新索引:ALTER TABLE class ADD INDEX X (card);

(6)第六步:第三次EXPLAIN:EXPLAIN SELECT * FROM class LEFT JOIN book ON class.card = book.card;
在这里插入图片描述(7)结论

  1. 在优化关联查询的时候,只有在被驱动表上建立索引才有效(只有在右表class上创建索引才有效)
  2. left join时,左侧的为驱动表book,右侧为被驱动表class
(1.2.3)inner join 案例(小表是驱动表,大表是被驱动表)

(1)内连接查询的时候,不管谁是左表右表,执行结果都一样。因为mysql会自动把小结果集的表选为驱动表,大结果集的表选为被驱动表。所以固定的class表是被驱动表,被驱动表上的索引才生效。

EXPLAIN SELECT * FROM book inner join class on class.card=book.card;

EXPLAIN SELECT * FROM class inner join book on class.card=book.card;

在这里插入图片描述

(1.2.4)建议

(1)保证被驱动表的join字段已经被索引
被驱动表 join 后的表为被驱动表 (需要被查询)
(2)left-join时,选择小表作为驱动表,大表做为被驱动表:但是 left join 时一定是左边是驱动表,右边是被驱动表。使用格式就是【大表(被驱动) left join 小表(驱动)】
(3)inner-join时,mysql会自己帮你把小结果集的表选为驱动表:mysql 自动选择。小表作为驱动表。因为 驱动表无论如何都会被全表扫描?。所以扫描次数越少越好
(4)子查询尽量不要放在被驱动表,子查询是虚表,不能建立索引,所以有可能使用不到索引
像下面这种子查询放在左表驱动表中

select a.name ,bc.name 
from t_emp a 
left join (select b.id , c.name from t_dept b inner join t_emp c on b.ceo = c.id)bc 
on bc.id = a.deptid.

上段查询中用到了子查询,必然 bc 表没有索引。肯定会进行全表扫描
上段查询 可以直接使用 两个 left join 优化

select a.name , c.name from t_emp a
left outer join t_dept b on a.deptid = b.id
left outer join t_emp c on b.ceo=c.id

所有条件都可以使用到索引

若必须用到子查询,可将子查询设置为驱动表,,因为驱动表的type 肯定是 all,而子查询返回的结果表没有索引,必定也是all

(1.2.5)4个关联查询案列分析

(1)子查询不要放在被驱动表,因为子查询是虚表,没法创建索引,而索引只有在右表被驱动表上才有效。
下面这个sql就是把子查询放在右表被驱动表中,t_emp表作为左表驱动表

EXPLAIN SELECT ed.name '人物',c.name '掌门' 
FROM (SELECT e.name,d.ceo from t_emp e LEFT JOIN t_dept d on e.deptid=d.id) ed 
LEFT JOIN t_emp c on ed.ceo= c.id;

下面这个sql就是把t_emp作为右表被驱动表,子查询放在左表驱动表

EXPLAIN SELECT e.name '人物',tmp.name '掌门' 
FROM t_emp e 
LEFT JOIN (SELECT d.id did,e.name FROM t_dept d LEFT JOIN t_emp e ON d.ceo=e.id)tmp ON e.deptId=tmp.did;

总结一下:
子查询尽量不要放在被驱动表,有可能使用不到索引;
left join时,尽量让实体表作为被驱动表。

(2)能够直接多表关联的尽量直接关联,不用子查询

EXPLAIN SELECT e1.name '人物',e2.name '掌门' 
FROM t_emp e1 
LEFT JOIN t_dept d on e1.deptid = d.id 
LEFT JOIN t_emp e2 on d.ceo = e2.id ;
Explain SELECT e2.name '人物', (SELECT e1.name FROM t_emp e1 where e1.id= d.ceo) '掌门' 
from t_emp e2 
LEFT JOIN t_dept d on e2.deptid=d.id;

(1.3)子查询优化

(1.3.1)用in还是exists

(1)有索引的情况下,用 inner join 是最好的 其次是 in ,exists最糟糕
(2)无索引的情况下,用小表驱动大表 因为join 方式需要distinct ,没有索引distinct消耗性能较大
所以 exists性能最佳 in其次 join性能最差?
(3)无索引的情况下,大表驱动小表,in 和 exists 的性能应该是接近的,都比较糟糕,exists稍微好一点,超不过5%,但是inner join 优于使用了 join buffer,所以快很多,如果left join 则最慢

(1.3.2)实验

(1)有索引 大表驱动小表
select sql_no_cache sum(sal) from emp where deptno in (select deptno from dept);
select sql_no_cache sum(sal) from emp where exists (select 1 from dept where emp.deptno=dept.deptno); ##用 exists 是否存在,存在返回一条记录,exists 是作为一个查询判断用,所以 select 后返回什么不重要。
select sql_no_cache sum(sal) from emp inner join dept on emp.deptno=dept.deptno;

(2)有索引 小表驱动大表(有索引小驱动大表 性能优于 大表驱动小表)
select sql_no_cache sum(e.sal) from (select * from emp where id<10000) e where exists (select 1 from emp where e.deptno=emp.deptno);
select sql_no_cache sum(e.sal) from (select * from emp where id<10000) e inner join (select distinct deptno from emp) m on m.deptno=e.deptno;
select sql_no_cache sum(sal) from emp where deptno in (select deptno from dept);

(3)无索引 小表驱动大表
select sql_no_cache sum(e.sal) from (select * from emp where id<10000) e where exists (select 1 from emp where e.deptno=emp.deptno);
select sql_no_cache sum(e.sal) from (select * from emp where id<10000) e inner join (select distinct deptno from emp) m on m.deptno=e.deptno;
select sql_no_cache sum(sal) from emp where deptno in (select deptno from dept);

(4)无索引大表驱动小表
select sql_no_cache sum(sal) from emp where deptno in (select deptno from dept);
select sql_no_cache sum(sal) from emp where exists (select 1 from dept where emp.deptno=dept.deptno);
select sql_no_cache sum(sal) from emp inner join dept on emp.deptno=dept.deptno;

(1.3.3)结论

有索引的情况下 用 inner join 是最好的 其次是 in ,exists最糟糕

无索引的情况下用
小表驱动大表 因为join 方式需要distinct ,没有索引distinct消耗性能较大
所以 exists性能最佳 in其次 join性能最差?

无索引的情况下大表驱动小表
in 和 exists 的性能应该是接近的 都比较糟糕 exists稍微好一点 超不过5% 但是inner join 优于使用了 join buffer 所以快很多
如果left join 则最慢

(1.3.4)案例分析:在范围判断时,尽量不要使用 not in 和 not exists,使用 left join on xxx is null 代替

(1)取出所有有不为掌门人的员工,按年龄分组

select age as '年龄', count(*) as '人数' 
from t_emp 
where id not in (select ceo from t_dept where ceo is not null) 
group by age;

(2)解决dept表的全表扫描,建立ceo字段的索引

create index idx_ceo on dept(ceo);

(3)进一步优化,替换not in

select age as '年龄', count(*) as '人数' 
from t_emp e 
left join t_dept d on e.id=d.ceo 
where d.id is null 
group by age;

(1.4)order by关键字优化

where条件和on的判断这些过滤条件,作为优先优化的部分,是要被先考虑的。其次,如果有分组和排序,也要考虑group by和order by

(1.4.1)order by子句,尽量使用index方式排序,避免使用FileSort方式排序

(1)建表sql

CREATE TABLE tblA(
  id int primary key not null auto_increment,
  age INT,
  birth TIMESTAMP NOT NULL,
  name varchar(200)
);
 
INSERT INTO tblA(age,birth,name) VALUES(22,NOW(),'abc');
INSERT INTO tblA(age,birth,name) VALUES(23,NOW(),'bcd');
INSERT INTO tblA(age,birth,name) VALUES(24,NOW(),'def');
 
CREATE INDEX idx_A_ageBirth ON tblA(age,birth,name);
 
SELECT * FROM tblA; 

(2)案例
(3)mysql支持两种方式的排序,FileSort和Index,index效率更高。它指mysql扫描索引本身完成排序。FileSort方式效率较低
(4)Order by满足两种情况,会使用index方式排序
order by语句使用索引最左前列
使用where子句与order by子句条件列组合满足索引最左前列
where子句中如果出现索引的范围查询(就是explain出现range)会导致order by索引失效

(5)尽可能在索引列上完成排序操作,遵照索引建的最佳左前缀
小总结
在这里插入图片描述
第二种中,where a = const and b > const order by b , c 不会出现 using filesort b , c 两个衔接上了
但是:where a = const and b > const order by c 将会出现 using filesort 。因为 b 用了范围索引,断了。而上一个 order by 后的b 用到了索引,所以能衔接上 c

(6)如果不在索引列上,filesort有两种算法:mysql就要启动双路排序和单路排序
1-双路排序
2-取一批数据,要对磁盘进行了两次扫描,IO是很耗时的,所以在mysql4.1之后,出现了第二种改进的算法,就是单路排序
3-单路排序:从磁盘读取查询需要的所有列,按照order by列在buffer对它们进行排序,然后扫描排序后的列表进行输出,它的效率更快一点,避免了第二次读取数据。并且把随机IO变成顺序IO,但是它会使用最多的空间,因为它把每一行都保存在内存中了
4-结论和引申出的问题
5-优化策略

(1.4.2)无过滤,不索引

无过滤,不索引。where,limit都相当于一种过滤条件,所以才能使用上索引!

create index idx_age_deptid_name on emp(age,deptid,name);
explain select * from emp where age=40 order by deptid;
explain select * from emp order by age,deptid;
explain select * from emp order by age,deptid limit 10;
(1.4.3)顺序错,必排序

(1)explain select * from emp where age=45 order by deptid,name;
(2)explain select * from emp where age=45 order by deptid,empno;
empno字段并没有建立索引,因此也无法用到索引,此字段需要排序
(3)explain select * from emp where age=45 order by name,deptid;
where两侧列的顺序可以变换,效果相同,但是order by列的顺序不能随便变换
(4)explain select * from emp where deptid=45 order by age;
deptid作为过滤条件的字段,无法使用索引,因此排序没法用上索引

(1.4.4)方向反,必排序

(1)explain select * from emp where age=45 order by deptid desc,name desc;
如果可以用上索引的字段都使用正序或者逆序,实际上是没有任何影响的,无非将结果集调换顺序
(2)explain select * from emp where age=45 order by deptid asc,name desc;
如果排序的字段,顺序有差异,就需要将差异的部分,进行一次倒置顺序,因此还是需要手动排序的

(1.4.5)索引的选择

(1)首先,清除emp上面的所有索引,只保留主键索引
drop index idx_age_deptid_name on emp;
(2)查询:且员工编号小于101000的用户,按用户名称排序
explain select sql_no_cache * from emp where age=30 and empno<101000 order by name;
(3)全表扫描肯定是不被允许的,因此我们要考虑优化
思路:首先需要让where的过滤条件,用上索引
查询中,age.empno是查询的过滤条件,而name则是排序的字段,因此我们来创建一个此三个字段的复合索引:create index idx_age_empno_name on emp(age,empno,name);

再次查询,发现using filesort依然存在
原因:empno是范围查询,因此导致了索引失效,索引name字段无法使用索引排序。所以,三个字段的复合索引,没有意义,因为empno和name字段只能选择其一。

(4)解决:empno和name二选其一

(1.5)分页查询的优化(limit)

(1.6)group by关键字优化

(1)group by使用索引的原则几乎跟order by一致,唯一区别就是groupby即使没有过滤条件用到索引,也可以直接使用索引。实质是先排序后进行分组,遵照索引建的最佳左前缀
(2)当无法使用索引列,增大max_length_for_sort_data参数的设置+增大sort_buffer_size参数的设置
(3)where高于having,能写在where限定的条件就不要去having限定了

(1.7)去重优化

尽量不要使用distinct,关键字去重优化
t_mall_sku 表
id shp_id kcdz


 3       1    北京市昌平区  
 4       1    北京市昌平区  
 5       5    北京市昌平区  
 6       3       重庆              
 8       8     天津              

例子:select kcdz form t_mall_sku where id in( 3,4,5,6,8 ) 将产生重复数据,
select distinct kcdz form t_mall_sku where id in( 3,4,5,6,8 ) 使用 distinct 关键字去重消耗性能
优化: select kcdz form t_mall_sku where id in( 3,4,5,6,8 ) group by kcdz 能够利用到索引

(1.8)使用覆盖索引

(1)什么是覆盖索引
创建索引的列已经包含所有要查询的数据,sql只需要通过索引就可以返回查询所需要的数据,不需要通过二级索引查到主键之后再去查询数据。

(1)介绍覆盖索引
如果一个索引包含所有需要查询的字段的值,就称为覆盖索引。就是包含了所有查询字段 (where,select,ordery by,group by 包含的字段) 的索引。

在InnoDB中,如果不是主键索引,叶子节点存储的主键+列值。最终还是要“回表”,也就是要通过主键再查找一次,这样也就是要通过主键再查找一次。这样就会比较慢覆盖索引就是把要查询出来的列和索引是对应的,不做回表操作。

覆盖索引即需要查询的字段正好是索引的字段,那么直接根据该索引,就可以查到数据了, 而无需回表查询。

如主键索引,如果一条SQL需要查询主键,那么正好根据主键索引就可以查到主键。
再如普通索引,如果一条SQL需要查询name,name字段正好有索引, 那么直接根据这个索引就可以查到数据,也无需回表。

(2)覆盖索引的好处
1-避免 Innodb 表进行索引的二次查询:Innodb 是以聚集索引的顺序来存储的,对于 Innodb 来说,二级索引在叶子节点中所保存的是行的主键信息,如果是用二级索引查询数据的话,在查找到相应的键值后,还要通过主键进行二次查询才能获取我们真实所需要的数据。而在覆盖索引中,二级索引的键值中可以获取所有的数据,避免了对主键的二次查询 ,减少了 IO 操作,提升了查询效率。
2-可以把随机 IO 变成顺序 IO 加快查询效率: 由于覆盖索引是按键值的顺序存储的,对于 IO 密集型的范围查找来说,对比随机从磁盘读取每一行的数据 IO 要少的多,因此利用覆盖索引在访问时也可以把磁盘的随机读取的 IO 转变成索引查找的顺序 IO。

(3)覆盖索引使用实例
现在创建索引(username,age),执行以下的sql语句。

select username , age from user where username = 'Java' and age = 22

在查询数据的时候:要查询出的列在叶子节点都存在!所以,就不用回表。

(1.9)using filesort

(1.9.1)mysql的排序算法

(1)双路排序
mysql4.1之前是使用双路排序,字面意思就是两次扫描磁盘,最终得到数据,读取行指针和order by列,对他们进行排序,然后扫描已经排序好的列表,按照列表中的值重新从列表中读取对应的数据输出。
从磁盘取排序字段,在buffer进行排序,再从磁盘取其他字段。
简单来说,取一批数据,要对磁盘进行两次扫描,但是IO是很耗时间的,所以在mysql4.1之后,出现了第二种改进算法,就是单路排序。

(2)单路排序
从磁盘读取查询需要的所有列,按照order by列在buffer对它们 进行排序,然后扫描排序后的列表进行输出,它的效率会更快一点,避免了第二次读取数据,并且把随机IO变成了顺序IO ,但是它会使用更多的空间,因为它把每一行都保存在内存中了

(3)单路排序的问题
由于单路是后出的,总体而言好过双路,但是存在以下问题:早sort_buffer中,方法B比方法A要多占用很多空间没因为方法B是把所有字段都取出,所以有可能取出的数据总大小超出了sort_buffer的容量,导致每次只能取sort_buffer容量大小的数据,进行排序(创建tmp文件么多路合并),排完再取sort_buffer容量大小,再排…从而多次IO

(4)结论:本来想省一次IO操作,反而导致了大量的IO操作,得不偿失

(5)如何优化
1)增大sort_buffer_size参数的设置
不管用哪种算法,提高这个参数都会提高效率,当然,要根据系统的能力去提高,因为这个参数是针对每个进程的1M-8M之间调整。
2)增大max_length_for_sort_data参数的设置
mysql使用单路排序的前提是排序的字段带下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值