mysql如何explan优化sql_《MySQL数据库》MySQL 优化SQL(explain)
前言
如果要寫出優(yōu)質(zhì)的SQL語句,就需要了解MySQL的存儲(chǔ)原理。MySQL是如何分析SQL,如何利用索引查詢。
Explain 關(guān)鍵字
explain select * from ic_base;? ? ? ? ? ? ? ? ? --查看SQL的執(zhí)行情況
id:執(zhí)行編號,標(biāo)識Select的執(zhí)行順序,存在子查詢等負(fù)責(zé)查詢的時(shí)候用來標(biāo)識執(zhí)行的優(yōu)先順序。
select_type:?select查詢語句的類型(simple,primary,subquery,derived,union,union result,dependent union,dependent subquery)。
>?simple : 簡單SQL
>?primary?: 包含union或者子查詢,最外層的部分標(biāo)記為primary
>?subquery?: 非相關(guān)子查詢(子查詢和主表之間有關(guān)聯(lián)關(guān)系)
>?derived?:?派生表——該臨時(shí)表是從子查詢派生出來的,位于form中的子查詢
>?union?: 包含union 或者 union all 的查詢
>?union result?: MySQL建立的臨時(shí)表需要去掉重復(fù)數(shù)據(jù)
>?dependent union?:?顧名思義,首先需要滿足UNION的條件,及UNION中第二個(gè)以及后面的SELECT語句,同時(shí)該語句依賴外部的查詢
>?dependent subquery?:?相關(guān)子查詢(子查詢和主表之間有關(guān)聯(lián)關(guān)系)
> materialized :當(dāng)查詢優(yōu)化器在執(zhí)行包含子查詢的語句時(shí),選擇將子查詢物化之后與外層查詢進(jìn)行連接查詢。
table:訪問的表名
partitions:分區(qū)信息
type:?訪問類型(system > const > eq_ref > ref > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL),innodb中不存在system.一般來說,得保證查詢至少達(dá)到range級別,最好能達(dá)到ref。
>?system?:?這是const連接類型的一種特例,表只有一行數(shù)據(jù)
> const?: 主鍵索引僅有一行滿足條件
> eq_ref?:?被驅(qū)動(dòng)表和驅(qū)動(dòng)表通過驅(qū)動(dòng)表的主鍵關(guān)聯(lián)。
> ref?: 輔助索引訪問,等值匹配或者常量匹配。
> ref_or_null?: 索引訪問,等值匹配或者常量匹配,存在null值。
> index_merge?:?合并索引,有多個(gè)索引可以選擇。
> unique_subquery?:?子查詢使用唯一索引
> index_subquery?:?子查詢使用索引
> range?:?范圍掃描,一個(gè)有限制的索引掃描。key列顯示使用了哪個(gè)索引。當(dāng)使用=、<>、>、>=、、BETWEEN 和IN 操作符,用常量比較關(guān)鍵字列時(shí)。
> index?:?和全表掃描一樣。只是掃描表的時(shí)候按照索引次序進(jìn)行而不是行。主要優(yōu)點(diǎn)就是避免了排序, 但是開銷仍然非常大。
> ALL :?全表掃描
possible_keys:顯示能夠使用的索引
key:使用的索引
key_len:使用的索引長度(使用的索引字段長度之和,字段沒有設(shè)置非空,需要加1,varchar 字段還要加2)
ref:關(guān)聯(lián)列或者常數(shù)
rows:數(shù)據(jù)行數(shù)(來自統(tǒng)計(jì)信息)
filtered:過濾百分比,可能滿足條數(shù)/總條數(shù)
Extra:MySQL的補(bǔ)充額外信息
> no tables used : 沒有額外信息
> Using where : 當(dāng)我們使用全表掃描來執(zhí)行對某個(gè)表的查詢,并且該語句的WHERE子句中有針對該表的搜索條件
> Using index: 當(dāng)我們的查詢列表以及搜索條件中只包含屬于某個(gè)索引的列,也就是在可以使用索引覆蓋的情況
> Impossible where: 查詢語句的WHERE子句永遠(yuǎn)為FALSE時(shí)將會(huì)提示該額外信息
> Using index condition:?有些搜索條件中雖然出現(xiàn)了索引列,但卻不能使用到索引
> no matching min/max row:?當(dāng)查詢列表處有MIN或者M(jìn)AX聚集函數(shù),但是并沒有符合WHERE子句中的搜索條件的記錄
> Using join buffer(block nested loop) : 在連接查詢執(zhí)行過程中,當(dāng)被驅(qū)動(dòng)表不能有效的利用索引加快訪問速度,MySQL一般會(huì)為其分配一塊名叫join
buffer的內(nèi)存塊來加快查詢速度
> Using filesort : 很多情況下排序操作無法使用到索引,只能在內(nèi)存中(記錄較少的時(shí)候)或者磁盤中(記錄較多的時(shí)候)進(jìn)行排序,這種在內(nèi)存中或者磁盤上進(jìn)行排序的方式統(tǒng)稱為文件排序(英文名:filesort)
> Using temporary : 在許多查詢的執(zhí)行過程中,MySQL可能會(huì)借助臨時(shí)表來完成一些功能,比如去重、排序之類的,比如我們在執(zhí)行許多包含DISTINCT、GROUP BY、UNION等子句的查詢過程中,如果不能有效利用索引來完成查詢,MySQL很有可能尋求通過建立內(nèi)部的臨時(shí)表來執(zhí)行查詢
> start temporary , end temporary: 查詢優(yōu)化器會(huì)優(yōu)先嘗試將IN子查詢轉(zhuǎn)換成semi-join,而semi-join又有好多種執(zhí)行策略,當(dāng)執(zhí)行策略為DuplicateWeedout時(shí),也就是通過建立臨時(shí)表來實(shí)現(xiàn)為外層查詢中的記錄進(jìn)行去重操作時(shí),驅(qū)動(dòng)表查詢執(zhí)行計(jì)劃的Extra列將顯示Start temporary提示,被驅(qū)動(dòng)表查詢執(zhí)行計(jì)劃的Extra列將顯示End temporary提示
> FirstMatch(表名) : 在將In子查詢轉(zhuǎn)為semi-join的去重的方式(找到一條就返回)
查詢優(yōu)化器
set optimizer_trace="enabled=on";? ? ? ?--打開查詢優(yōu)化器
---------------需要執(zhí)行的SQL(可以使用explain)-------------------------
select * from information_schema.OPTIMIZER_TRACE? ? ?--查詢優(yōu)化器的執(zhí)行結(jié)果
set optimizer_trace="enabled=off";? ? ? ?--關(guān)閉查詢優(yōu)化器
查詢優(yōu)化器查詢的結(jié)果
query: 對應(yīng)SQL.
trace :優(yōu)化過程(里面有行估算,走索引,最左前綴等一些計(jì)算成本的過程,然后MySQL自動(dòng)選擇一種最優(yōu)方式)。
成本計(jì)算公式:全表掃描的公式: 主鍵索引頁數(shù)*1 + 行數(shù)*0.2 = Data_length/16K + Rows*0.2 ;? ? 主鍵索引頁數(shù),行數(shù)來自統(tǒng)計(jì)信息, 其他數(shù)據(jù)為MySQL固定常量
由于MySQL的成本計(jì)算也是估算(99%是靠譜的),但是當(dāng)遇到很復(fù)雜的SQL,或者統(tǒng)計(jì)信息與實(shí)際情況差距太大的時(shí)候,會(huì)導(dǎo)致MySQL的優(yōu)化過程出現(xiàn)問題。
這個(gè)時(shí)候我們需要干擾MySQL的執(zhí)行計(jì)劃,強(qiáng)制走我們需要的索引或者更新統(tǒng)計(jì)信息。
索引失效
1. 隱式轉(zhuǎn)換,不走索引
表ic_website的url 創(chuàng)建了一個(gè)普通索引,并且該字段是varchar類型,會(huì)出現(xiàn)一下情況:
explain select * from ic_website where url = '123';? ? --? 索引有效
explain select * from ic_website where url = 123;? ? --? 索引失效
2. <>,not in 不走普通索引,主鍵索引還是可以走索引。
explain select * from ic_website where url <> '123';
3. 左邊有% 的不走索引
explain select * from ic_website where url like '%123';
實(shí)戰(zhàn)
一、ANALYZE TABLE? ic_base;? ?-- 重新收集ic_base 的統(tǒng)計(jì)信息,保證MySQL優(yōu)化器計(jì)算準(zhǔn)確。 查看統(tǒng)計(jì)信息是否被更新:select * from mysql.innodb_table_stats;
select * from mysql.innodb_index_stats;
二、hints
USE INDEX:限制索引的使用范圍,們在數(shù)據(jù)表里建立了很多索引,當(dāng)MySQL對索引進(jìn)行選擇 時(shí),這些索引都在考慮的范圍內(nèi)。但有時(shí)我們希望MySQL只考慮幾個(gè)索引,而不是全部的索引, 這就需要用到USE INDEX對查詢語句進(jìn)行設(shè)置。
IGNORE INDEX :限制不使用索引的范圍
FORCE INDEX:我們希望MySQL必須要使用某一個(gè)索引(由于 MySQL在查詢時(shí)只能使用一個(gè)索 引,因此只能強(qiáng)迫MySQL使用一個(gè)索引)。這就需要使用FORCE INDEX來完成這個(gè)功能。
hints 語法:
SELECT * FROM table1 USE|IGNORE|FORCE INDEX (col1_index,col2_index) WHERE col1=1 ANDcol2=2 AND col3=3;
三、straight_join? ?-- 強(qiáng)制改成左邊為驅(qū)動(dòng)表
select t1.* fromTable1 t1 STRAIGHT_JOIN Table2 t2on t1.CommonID = t2.CommonID where t1.FilterID = 1
總結(jié)
SQL優(yōu)化伴隨開發(fā)的全部過程,隨著時(shí)間和業(yè)務(wù)的推移,一些SQL的性能跟不上了,需要重新整理和優(yōu)化。
筆者遇到過好幾千行的SQL(union,子查詢,嵌套查詢,函數(shù),分組,排序)幾乎用了SQL的全部特性,優(yōu)化這類SQL第一要熟悉SQL的作用,第二點(diǎn)要將這類SQL拆小,先找到慢的地方,然后再考慮優(yōu)化。優(yōu)化SQL是一個(gè)需要耐心的活,平時(shí)一定要注意SQL寫法,盡量避免一些糟糕的寫法,減少后期的維護(hù)。
總結(jié)
以上是生活随笔為你收集整理的mysql如何explan优化sql_《MySQL数据库》MySQL 优化SQL(explain)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql字段说明_mysql 字段类型
- 下一篇: 运行mysql数据库的命令_mysql