mysql优化-实战

单表优化

createtablebook
(
bidint(4)primarykey,
namevarchar(20)notnull,
authoridint(4)notnull,
publicidint(4)notnull,
typeidint(4)notnull
);

insertintobookvalues(1,'tjava',1,1,2);
insertintobookvalues(2,'tc',2,1,2);
insertintobookvalues(3,'wx',3,2,1);
insertintobookvalues(4,'math',4,2,3);
commit;

查询authorid=1且typeid为2或3的bid
explainselectbidfrombookwheretypeidin(2,3)andauthorid=1orderbytypeiddesc;

(a,b,c)
(a,b)

优化:加索引
altertablebookaddindexidx_bta(bid,typeid,authorid);

索引一旦进行升级优化,需要将之前废弃的索引删掉,防止干扰。
dropindexidx_btaonbook;

根据SQL实际解析的顺序,调整索引的顺序:
altertablebookaddindexidx_tab(typeid,authorid,bid);--虽然可以回表查询bid,但是将bid放到索引中可以提升使用usingindex;

再次优化(之前是index级别):思路。因为范围查询in有时会实现,因此交换索引的顺序,将typeidin(2,3)放到最后。
dropindexidx_tabonbook;
altertablebookaddindexidx_atb(authorid,typeid,bid);
explainselectbidfrombookwhereauthorid=1andtypeidin(2,3)orderbytypeiddesc;

--小结:a.最佳做前缀,保持索引的定义和使用的顺序一致性b.索引需要逐步优化c.将含In的范围查询放到where条件的最后,防止失效。

本例中同时出现了Usingwhere(需要回原表);Usingindex(不需要回原表):原因,whereauthorid=1andtypeidin(2,3)中authorid在索引(authorid,typeid,bid)中,因此不需要回原表(直接在索引表中能查到);而typeid虽然也在索引(authorid,typeid,bid)中,但是含in的范围查询已经使该typeid索引失效,因此相当于没有typeid这个索引,所以需要回原表(usingwhere);
例如以下没有了In,则不会出现usingwhere
explainselectbidfrombookwhereauthorid=1andtypeid=3orderbytypeiddesc;

还可以通过key_len证明In可以使索引失效。

两表优化

createtableteacher2
(
tidint(4)primarykey,
cidint(4)notnull
);

insertintoteacher2values(1,2);
insertintoteacher2values(2,1);
insertintoteacher2values(3,3);

createtablecourse2
(
cidint(4),
cnamevarchar(20)
);

insertintocourse2values(1,'java');
insertintocourse2values(2,'python');
insertintocourse2values(3,'kotlin');
commit;

左连接:
explainselect*fromteacher2tleftouterjoincourse2c
ont.cid=c.cidwherec.cname='java';

索引往哪张表加?-小表驱动大表
-索引建立经常使用的字段上(本题t.cid=c.cid可知,t.cid字段使用频繁,因此给该字段加索引)[一般情况对于左外连接,给左表加索引;右外连接,给右表加索引]
小表:10
大表:300
where小表.x10=大表.y300;--循环了几次?10

大表.y300=小表.x10--循环了300次

小表:10
大表:300

select...where小表.x10=大表.x300;
for(inti=0;i<小表.length10;i++)
{
for(intj=0;j<大表.length300;j++)
{
...
}
}

select...where大表.x300=小表.x10;
for(inti=0;i<大表.length300;i++)
{
for(intj=0;j<小表.length10;j++)
{
...
}
}

--以上2个FOR循环,最终都会循环3000次;但是对于双层循环来说:一般建议将数据小的循环放外层;数据大的循环放内存。

--当编写..ont.cid=c.cid时,将数据量小的表放左边(假设此时t表数据量小)

altertableteacher2addindexindex_teacher2_cid(cid);
altertablecourse2addindexindex_course2_cname(cname);

Usingjoinbuffer:extra中的一个选项,作用:Mysql引擎使用了连接缓存。

三张表优化

ABC
a.小表驱动大表b.索引建立在经常查询的字段上

示例:
createtabletest03
(
a1int(4)notnull,
a2int(4)notnull,
a3int(4)notnull,
a4int(4)notnull
);
altertabletest03addindexidx_a1_a2_a3_4(a1,a2,a3,a4);

explainselecta1,a2,a3,a4fromtest03wherea1=1anda2=2anda3=3anda4=4;--推荐写法,因为索引的使用顺序(where后面的顺序)和复合索引的顺序一致

explainselecta1,a2,a3,a4fromtest03wherea4=1anda3=2anda2=3anda1=4;--虽然编写的顺序和索引顺序不一致,但是sql在真正执行前经过了SQL优化器的调整,结果与上条SQL是一致的。
--以上2个SQL,使用了全部的复合索引

explainselecta1,a2,a3,a4fromtest03wherea1=1anda2=2anda4=4orderbya3;
--以上SQL用到了a1a2两个索引,该两个字段不需要回表查询usingindex;而a4因为跨列使用,造成了该索引失效,需要回表查询因此是usingwhere;以上可以通过key_len进行验证

explainselecta1,a2,a3,a4fromtest03wherea1=1anda4=4orderbya3;
--以上SQL出现了usingfilesort(文件内排序,“多了一次额外的查找/排序”):不要跨列使用(where和orderby拼起来,不要跨列使用)

explainselecta1,a2,a3,a4fromtest03wherea1=1anda4=4orderbya2,a3;--不会usingfilesort

--总结:i.如果(a,b,c,d)复合索引和使用的顺序全部一致(且不跨列使用),则复合索引全部使用。如果部分一致(且不跨列使用),则使用部分索引。
selecta,cwherea=andb=andd=
ii.where和orderby拼起来,不要跨列使用

usingtemporary:需要额外再多使用一张表.一般出现在groupby语句中;已经有表了,但不适用,必须再来一张表。
解析过程:
from..on..join..where..groupby....having...selectdinstinct..orderbylimit...
a.
explainselectfromtest03wherea2=2anda4=4groupbya2,a4;--没有usingtemporary
b.
explainselect
fromtest03wherea2=2anda4=4groupbya3;

避免索引失效的一些原则

(1)复合索引
a.复合索引,不要跨列或无序使用(最佳左前缀)
(a,b,c)
b.复合索引,尽量使用全索引匹配
(a,b,c)
(2)不要在索引上进行任何操作(计算、函数、类型转换),否则索引失效
select..whereA.x=..;--假设A.x是索引
不要:select..whereA.x3=..;
explainselect
frombookwhereauthorid=1andtypeid=2;--用到了at2个索引
explainselectfrombookwhereauthorid=1andtypeid2=2;--用到了a1个索引
explainselectfrombookwhereauthorid2=1andtypeid2=2;----用到了0个索引
explainselect
frombookwhereauthorid*2=1andtypeid=2;----用到了0个索引,原因:对于复合索引,如果左边失效,右侧全部失效。(a,b,c),例如如果b失效,则bc同时失效。

dropindexidx_atbonbook;
altertablebookaddindexidx_authroid(authorid);
altertablebookaddindexidx_typeid(typeid);
explainselectfrombookwhereauthorid2=1andtypeid=2;
(3)复合索引不能使用不等于(!=<>)或isnull(isnotnull),否则自身以及右侧所有全部失效。
复合索引中如果有>,则自身和右侧索引全部失效。

explainselect*frombookwhereauthorid=1andtypeid=2;

--SQL优化,是一种概率层面的优化。至于是否实际使用了我们的优化,需要通过explain进行推测。

explainselectfrombookwhereauthorid!=1andtypeid=2;
explainselect
frombookwhereauthorid!=1andtypeid!=2;

体验概率情况(<>=):原因是服务层中有SQL优化器,可能会影响我们的优化。
dropindexidx_typeidonbook;
dropindexidx_authroidonbook;
altertablebookaddindexidx_book_at(authorid,typeid);
explainselectfrombookwhereauthorid=1andtypeid=2;--复合索引at全部使用
explainselect
frombookwhereauthorid>1andtypeid=2;--复合索引中如果有>,则自身和右侧索引全部失效。
explainselectfrombookwhereauthorid=1andtypeid>2;--复合索引at全部使用
----明显的概率问题---
explainselect
frombookwhereauthorid<1andtypeid=2;--复合索引at只用到了1个索引
explainselect*frombookwhereauthorid<4andtypeid=2;--复合索引全部失效

--我们学习索引优化,是一个大部分情况适用的结论,但由于SQL优化器等原因该结论不是100%正确。
--一般而言,范围查询(><in),之后的索引失效。

(4)补救。尽量使用索引覆盖(usingindex)
(a,b,c)
selecta,b,cfromxx..wherea=..andb=..;

(5)like尽量以“常量”开头,不要以'%'开头,否则索引失效
select*fromxxwherenamelike'%x%';--name索引失效

explainselect*fromteacherwheretnamelike'%x%';--tname索引失效

explainselect*fromteacherwheretnamelike'x%';

explainselecttnamefromteacherwheretnamelike'%x%';--如果必须使用like'%x%'进行模糊查询,可以使用索引覆盖挽救一部分。

(6)尽量不要使用类型转换(显示、隐式),否则索引失效
explainselectfromteacherwheretname='abc';
explainselect
fromteacherwheretname=123;//程序底层将123->'123',即进行了类型转换,因此索引失效

(7)尽量不要使用or,否则索引失效
explainselect*fromteacherwheretname=''ortcid>1;--将or左侧的tname失效。

一些其他的优化方法

(1)
exist和in
select..fromtablewhereexist(子查询);
select..fromtablewhere字段in(子查询);

如果主查询的数据集大,则使用In,效率高。
如果子查询的数据集大,则使用exist,效率高。

exist语法:将主查询的结果,放到子查需结果中进行条件校验(看子查询是否有数据,如果有数据则校验成功),
如果复合校验,则保留数据;

selecttnamefromteacherwhereexists(select*fromteacher);
--等价于selecttnamefromteacher

selecttnamefromteacherwhereexists(select*fromteacherwheretid=9999);

in:
select..fromtablewheretidin(1,3,5);

(2)orderby优化
usingfilesort有两种算法:双路排序、单路排序(根据IO的次数)
MySQL4.1之前默认使用双路排序;双路:扫描2次磁盘(1:从磁盘读取排序字段,对排序字段进行排序(在buffer中进行的排序)2:扫描其他字段)
--IO较消耗性能
MySQL4.1之后默认使用单路排序:只读取一次(全部字段),在buffer中进行排序。但种单路排序会有一定的隐患(不一定真的是“单路|1次IO”,有可能多次IO)。原因:如果数据量特别大,则无法将所有字段的数据一次性读取完毕,因此会进行“分片读取、多次读取”。
注意:单路排序比双路排序会占用更多的buffer。
单路排序在使用时,如果数据大,可以考虑调大buffer的容量大小:setmax_length_for_sort_data=1024单位byte

如果max_length_for_sort_data值太低,则mysql会自动从单路->双路(太低:需要排序的列的总大小超过了max_length_for_sort_data定义的字节数)

提高orderby查询的策略:
a.选择使用单路、双路;调整buffer的容量大小;
b.避免select*...
c.复合索引不要跨列使用,避免usingfilesort
d.保证全部的排序字段排序的一致性(都是升序或降序)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352

推荐阅读更多精彩内容