原因:
性能低亡呵、執(zhí)行時間太長絮供、等待時間太長、SQL語句欠佳(連接查詢)帆赢、索引失效小压、服務(wù)器參數(shù)設(shè)置不合理(緩沖、線程數(shù))
SQL解析過程
編寫過程:
selectdinstinct..from..join..on..where..groupby...having..orderby..limit..
解析過程:
from..on..join..where..groupby....having...selectdinstinct..orderbylimit...
索引
主要就是在優(yōu)化索引
索引:相當(dāng)于書的目錄
索引:index是幫助MYSQL高效獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)椰于。索引是數(shù)據(jù)結(jié)構(gòu)(樹:B樹(默認(rèn))怠益、Hash樹...)
索引的弊端:
1.索引本身很大,可以存放在內(nèi)存/硬盤(通常為硬盤)
2.索引不是所有情況均適用:a.少量數(shù)據(jù)b.頻繁更新的字段c.很少使用的字段
3.索引會降低增刪改的效率(增刪改查)
索引的優(yōu)勢:
1.提高查詢效率(降低IO使用率)
2.降低CPU使用率(...orderbyagedesc,因?yàn)锽樹索引本身就是一個好排序的結(jié)構(gòu)瘾婿,因此在排序時可以直接使用)
分類:
主鍵索引:不能重復(fù)蜻牢。id不能是null
唯一索引:不能重復(fù)。id可以是null
單值索引:單列偏陪,age;一個表可以多個單值索引,name抢呆。
復(fù)合索引:多個列構(gòu)成的索引(相當(dāng)于二級目錄:z:zhao)(name,age)(a,b,c,d,...,n)
創(chuàng)建索引:
方式一:create索引類型索引名on表(字段)
單值:
createindexdept_indexontb(dept);
唯一:
createuniqueindexname_indexontb(name);
復(fù)合索引
createindexdept_name_indexontb(dept,name);
方式二:altertable表名索引類型索引名(字段)
單值:
altertabletbaddindexdept_index(dept);
唯一:
altertabletbadduniqueindexname_index(name);
復(fù)合索引
altertabletbaddindexdept_name_index(dept,name);
注意:如果一個字段是primarykey,則改字段默認(rèn)就是主鍵索引
刪除索引:
dropindex索引名on表名;
dropindexname_indexontb;
查詢索引:
showindexfrom表名;
showindexfrom表名\G
SQL性能問題
a.分析SQL的執(zhí)行計(jì)劃:explain笛谦,可以模擬SQL優(yōu)化器執(zhí)行SQL語句抱虐,從而讓開發(fā)人員知道自己編寫的SQL狀況
b.MySQL查詢優(yōu)化其會干擾我們的優(yōu)化
查詢執(zhí)行計(jì)劃:
explain+SQL語句
explainselect*fromtb;
id:編號
select_type:查詢類型
table:表
type:類型
possible_keys:預(yù)測用到的索引
key:實(shí)際使用的索引
key_len:實(shí)際使用索引的長度
ref:表之間的引用
rows:通過索引查詢到的數(shù)據(jù)量
Extra:額外的信息
準(zhǔn)備數(shù)據(jù):
createtablecourse
(
cidint(3),
cnamevarchar(20),
tidint(3)
);
createtableteacher
(
tidint(3),
tnamevarchar(20),
tcidint(3)
);
createtableteacherCard
(
tcidint(3),
tcdescvarchar(200)
);
insertintocoursevalues(1,'java',1);
insertintocoursevalues(2,'html',1);
insertintocoursevalues(3,'sql',2);
insertintocoursevalues(4,'web',3);
insertintoteachervalues(1,'tz',1);
insertintoteachervalues(2,'tw',2);
insertintoteachervalues(3,'tl',3);
insertintoteacherCardvalues(1,'tzdesc');
insertintoteacherCardvalues(2,'twdesc');
insertintoteacherCardvalues(3,'tldesc');
查詢課程編號為2或教師證編號為3的老師信息
explain+sql:
(1)id:
id值相同,從上往下順序執(zhí)行饥脑。
t3-tc3-c4
tc3--c4-t6
表的執(zhí)行順序因數(shù)量的個數(shù)改變而改變的原因:笛卡兒積
abc
432=23=64=24
34=122=24
數(shù)據(jù)小的表優(yōu)先查詢恳邀;
id值不同:id值越大越優(yōu)先查詢
(本質(zhì):在嵌套子查詢時,先查內(nèi)層再查外層)
查詢教授SQL課程的老師的描述(desc)
explainselecttc.tcdescfromteacherCardtc,coursec,teachertwherec.tid=t.tid
andt.tcid=tc.tcidandc.cname='sql';
將以上多表查詢轉(zhuǎn)為子查詢形式:
explainselecttc.tcdescfromteacherCardtcwheretc.tcid=
(selectt.tcidfromteachertwheret.tid=
(selectc.tidfromcoursecwherec.cname='sql')
);
子查詢+多表:
explainselectt.tname,tc.tcdescfromteachert,teacherCardtcwheret.tcid=tc.tcid
andt.tid=(selectc.tidfromcoursecwherecname='sql');
id值有相同好啰,又有不同:id值越大越優(yōu)先轩娶;id值相同儿奶,從上往下順序執(zhí)行
(2)select_type:查詢類型
PRIMARY:包含子查詢SQL中的主查詢(最外層)
SUBQUERY:包含子查詢SQL中的子查詢(非最外層)
simple:簡單查詢(不包含子查詢框往、union)
derived:衍生查詢(使用到了臨時表)
a.在from子查詢中只有一張表
explainselectcr.cnamefrom(select*fromcoursewheretidin(1,2))cr;
b.在from子查詢中,如果有table1uniontable2闯捎,則table1就是derived,table2就是union
explainselectcr.cnamefrom(selectfromcoursewheretid=1unionselectfromcoursewheretid=2)cr;
union:上例
unionresult:告知開發(fā)人員椰弊,那些表之間存在union查詢
system>const>eq_ref>ref>fulltext>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>ALL
(3)type:索引類型许溅、類型
system>const>eq_ref>ref>range>index>all,要對type進(jìn)行優(yōu)化的前提:有索引
其中:system,const只是理想情況秉版;實(shí)際能達(dá)到ref>range
system(忽略):只有一條數(shù)據(jù)的系統(tǒng)表贤重;或衍生表只有一條數(shù)據(jù)的主查詢
createtabletest01
(
tidint(3),
tnamevarchar(20)
);
insertintotest01values(1,'a');
commit;
增加索引
altertabletest01addconstrainttid_pkprimarykey(tid);
explainselectfrom(selectfromtest01)twheretid=1;
const:僅僅能查到一條數(shù)據(jù)的SQL,用于Primarykey或unique索引(類型與索引類型有關(guān))
explainselecttidfromtest01wheretid=1;
altertabletest01dropprimarykey;
createindextest01_indexontest01(tid);
eq_ref:唯一性索引:對于每個索引鍵的查詢,返回匹配唯一行數(shù)據(jù)(有且只有1個清焕,不能多并蝗、不能0)
select...from..wherename=....常見于唯一索引和主鍵索引。
altertableteacherCardaddconstraintpk_tcidprimarykey(tcid);
altertableteacheraddconstraintuk_tciduniqueindex(tcid);
explainselectt.tcidfromteachert,teacherCardtcwheret.tcid=tc.tcid;
以上SQL秸妥,用到的索引是t.tcid,即teacher表中的tcid字段滚停;
如果teacher表的數(shù)據(jù)個數(shù)和連接查詢的數(shù)據(jù)個數(shù)一致(都是3條數(shù)據(jù)),則有可能滿足eq_ref級別粥惧;否則無法滿足键畴。
ref:非唯一性索引,對于每個索引鍵的查詢突雪,返回匹配的所有行(0起惕,多)
準(zhǔn)備數(shù)據(jù):
insertintoteachervalues(4,'tz',4);
insertintoteacherCardvalues(4,'tz222');
測試:
altertableteacheraddindexindex_name(tname);
explainselect*fromteacherwheretname='tz';
range:檢索指定范圍的行,where后面是一個范圍查詢(between,><>=,特殊:in有時候會失效,從而轉(zhuǎn)為無索引all)
altertableteacheraddindextid_index(tid);
explainselectt.fromteachertwheret.tidin(1,2);
explainselectt.fromteachertwheret.tid<3;
index:查詢?nèi)克饕袛?shù)據(jù)
explainselecttidfromteacher;--tid是索引咏删,只需要掃描索引表惹想,不需要所有表中的所有數(shù)據(jù)
all:查詢?nèi)勘碇械臄?shù)據(jù)
explainselectcidfromcourse;--cid不是索引,需要全表所有督函,即需要所有表中的所有數(shù)據(jù)
system/const:結(jié)果只有一條數(shù)據(jù)
eq_ref:結(jié)果多條勺馆;但是每條數(shù)據(jù)是唯一的;
ref:結(jié)果多條侨核;但是每條數(shù)據(jù)是是0或多條草穆;
(4)possible_keys:可能用到的索引,是一種預(yù)測搓译,不準(zhǔn)悲柱。
altertablecourseaddindexcname_index(cname);
explainselectt.tname,tc.tcdescfromteachert,teacherCardtc
wheret.tcid=tc.tcid
andt.tid=(selectc.tidfromcoursecwherecname='sql');
如果possible_key/key是NULL,則說明沒用索引
explainselecttc.tcdescfromteacherCardtc,coursec,teachertwherec.tid=t.tid
andt.tcid=tc.tcidandc.cname='sql';
(5)key:實(shí)際使用到的索引
(6)key_len:索引的長度;
作用:用于判斷復(fù)合索引是否被完全使用(a,b,c)些己。
createtabletest_kl
(
namechar(20)notnulldefault''
);
altertabletest_kladdindexindex_name(name);
explainselect*fromtest_klwherename='';--key_len:60
在utf8:1個字符站3個字節(jié)
altertabletest_kladdcolumnname1char(20);--name1可以為null
altertabletest_kladdindexindex_name1(name1);
explainselect*fromtest_klwherename1='';
--如果索引字段可以為Null,則會使用1個字節(jié)用于標(biāo)識豌鸡。
dropindexindex_nameontest_kl;
dropindexindex_name1ontest_kl;
增加一個復(fù)合索引
altertabletest_kladdindexname_name1_index(name,name1);
explainselectfromtest_klwherename1='';--121
explainselectfromtest_klwherename='';--60
varchar(20)
altertabletest_kladdcolumnname2varchar(20);--可以為Null
altertabletest_kladdindexname2_index(name2);
explainselectfromtest_klwherename2='';--63
203=60+1(null)+2(用2個字節(jié)標(biāo)識可變長度)=63
utf8:1個字符3個字節(jié)
gbk:1個字符2個字節(jié)
latin:1個字符1個字節(jié)
(7)ref:注意與type中的ref值區(qū)分。
作用:指明當(dāng)前表所參照的字段段标。
select....wherea.c=b.x;(其中b.x可以是常量涯冠,const)
altertablecourseaddindextid_index(tid);
explainselect*fromcoursec,teachertwherec.tid=t.tidandt.tname='tw';
(8)rows:被索引優(yōu)化查詢的數(shù)據(jù)個數(shù)(實(shí)際通過索引而查詢到的數(shù)據(jù)個數(shù))
explainselect*fromcoursec,teachertwherec.tid=t.tid
andt.tname='tz';
(9)Extra:
(i).usingfilesort:性能消耗大;需要“額外”的一次排序(查詢)逼庞。常見于orderby語句中蛇更。
排序:先查詢
10個人根據(jù)年齡排序。
createtabletest02
(
a1char(3),
a2char(3),
a3char(3),
indexidx_a1(a1),
indexidx_a2(a2),
indexidx_a3(a3)
);
explainselect*fromtest02wherea1=''orderbya1;
a1:姓名a2:年齡
explainselect*fromtest02wherea1=''orderbya2;--usingfilesort
小結(jié):對于單索引,如果排序和查找是同一個字段派任,則不會出現(xiàn)usingfilesort砸逊;如果排序和查找不是同一個字段,則會出現(xiàn)usingfilesort掌逛;
避免:where哪些字段师逸,就orderby那些字段2
復(fù)合索引:不能跨列(最佳左前綴)
dropindexidx_a1ontest02;
dropindexidx_a2ontest02;
dropindexidx_a3ontest02;
altertabletest02addindexidx_a1_a2_a3(a1,a2,a3);
explainselectfromtest02wherea1=''orderbya3;--usingfilesort
explainselectfromtest02wherea2=''orderbya3;--usingfilesort
explainselectfromtest02wherea1=''orderbya2;
explainselectfromtest02wherea2=''orderbya1;--usingfilesort
小結(jié):避免:where和orderby按照復(fù)合索引的順序使用,不要跨列或無序使用豆混。
(ii).usingtemporary:性能損耗大篓像,用到了臨時表。一般出現(xiàn)在groupby語句中皿伺。
explainselecta1fromtest02wherea1in('1','2','3')groupbya1;
explainselecta1fromtest02wherea1in('1','2','3')groupbya2;--usingtemporary
避免:查詢那些列遗淳,就根據(jù)那些列g(shù)roupby.
(iii).usingindex:性能提升;索引覆蓋(覆蓋索引)。原因:不讀取原文件心傀,只從索引文件中獲取數(shù)據(jù)(不需要回表查詢)
只要使用到的列全部都在索引中屈暗,就是索引覆蓋usingindex
例如:test02表中有一個復(fù)合索引(a1,a2,a3)
explainselecta1,a2fromtest02wherea1=''ora2='';--usingindex
dropindexidx_a1_a2_a3ontest02;
altertabletest02addindexidx_a1_a2(a1,a2);
explainselecta1,a3fromtest02wherea1=''ora3='';
如果用到了索引覆蓋(usingindex時),會對possible_keys和key造成影響:
a.如果沒有where脂男,則索引只出現(xiàn)在key中养叛;
b.如果有where,則索引出現(xiàn)在key和possible_keys中宰翅。
explainselecta1,a2fromtest02wherea1=''ora2='';
explainselecta1,a2fromtest02;
(iii).usingwhere(需要回表查詢)
假設(shè)age是索引列
但查詢語句selectage,namefrom...whereage=...,此語句中必須回原表查Name弃甥,因此會顯示usingwhere.
explainselecta1,a3fromtest02wherea3='';--a3需要回原表查詢
(iv).impossiblewhere:where子句永遠(yuǎn)為false
explainselect*fromtest02wherea1='x'anda1='y';