mysql執(zhí)行計劃

執(zhí)行計劃分析

什么是執(zhí)行計劃?

select * from? city where sname='張飛';

分析的是優(yōu)化器按照內(nèi)置的代價計算模型算法,

最終選擇后的執(zhí)行計劃。



cost ? 代價,成本

對于計算機來講,代價是什么?

io,cpu,mem?

查看執(zhí)行計劃?

mysql> explain select * from world.city;

+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+

| id | select_type | table | partitions | type | possible_keys | key? | key_len | ref? | rows | filtered | Extra |

+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+

|? 1 | SIMPLE? ? ? | city? | NULL? ? ? | ALL? | NULL? ? ? ? ? | NULL | NULL? ? | NULL | 4046 |? 100.00 | NULL? |

+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+

1 row in set, 1 warning (0.00 sec)

執(zhí)行計劃顯示結(jié)果的分析

table? :此次查詢涉及到的表

type? :查詢類型:全表掃,索引掃

possible_keys :可能會用到的索引

key :最后選擇的索引

key_len :索引的覆蓋長度?

rows :此次查詢需要掃描的行數(shù)

Extra :額外的信息


詳細分析

table:此次分析所涉及到的表,多對查詢時,定位到有問題的表

type 查詢類型

全表掃描 : 不會利用到所有的索引 ALL?

例如:select * from city;

select * from city? where sname = like '%y%';

select * from city? where sname not in? '張飛';

索引掃描 : index? < range < ref < eq_ref < const(system)

index :全索引掃描?

desc select contrycode from world ;contrycode有索引

range:索引范圍查詢: > < >= <= like in or between and?

desc select countrycode from world.city where id > 10;

desc select countrycode from world.city where countrycode? like 'F%';

desc select * from city where countrycode in ('USA','CHN');

特殊情況:查詢條件為主鍵是可以走range 范圍查詢

!= 和 not in? 會自動拆分為范圍查詢

ref :? 輔助索引的等值查詢?

desc select * from city where countrycode = ('USA');

eq_ref :多表鏈接中,非驅(qū)動表的鏈接條件是主鍵或唯一鍵.

a join b? on a.xx = b.yy??

desc select c.name,l.name from city c join country l

on c.`CountryCode` = l.`Code` where c.`Name`='Shanghai';

const(system):聚簇索引等值查詢。

desc select * from city where id=1;

possible_keys 可能用到的索引,所有和此次查詢有關(guān)的索引情況

key:當(dāng)次查詢選擇的索引

key_len :聯(lián)合索引的覆蓋長度

例如:index(a,b,c) 我們希望我們的查詢,對聯(lián)合索引,應(yīng)用的越充分越好,

key_len可以幫我判斷,此次查詢走了聯(lián)合索引的幾部分.

假設(shè),某條查詢可以完全覆蓋三列聯(lián)合索引

select? * from t1 where a=? and b =? and c =?

ken_len = a長度 ? + b長度? + c長度?

長度受到 數(shù)據(jù)類型? 字符集 影響??

長度指的是,列的最大的字節(jié)存儲長度

數(shù)字:

? ? ? ? ?not null? ? ?沒有not null??

tinyint? 1字節(jié)? ? ?1+ 1?

int? 4字節(jié)? ? ? ? ? ?4+ 1?

bigint? 8字節(jié)? ? ? 8 + 1?

key_len:

a int not null --->4

a int? ? ?---->5


字符: utf8------->一個字符最大占3個字節(jié)

? ? ? ? ? ? ? ? ? ? ? ? not null? ? ? ?沒有not null

?char(10)? ? ? ? ? ? 3* 10? ? ? ? ? 3*10 +1?

varchar(10)? ? ? 3* 10 + 2(最多占用2個字節(jié)存儲字符的長度)? ? ? ? ? 3*10 + 2+ 1?

b char(10) not null 30?

b char(10)? ? ? ? ? ? ? ?31?

c varchar(10) not null 32?

c? varchar(10)? ? ?33??

字符: utf8mb4------->一個字符最大占4個字節(jié)

? ? ? ? ? ? ? ? ? ? ? ? not null? ? ? ?沒有not null

?char(10)? ? ? ? ? ? 4* 10? ? ? ? ? 4*10 +1?

varchar(10)? ? ? 4* 10 + 2(最多占用2個字節(jié)存儲字符的長度)? ? ? ? ? 4*10 + 2+ 1?

b char(10) not null 40?

b char(10)? ? ? ? ? ? ? ?41?

c varchar(10) not null 42?

c? varchar(10)? ? ?43??

create table t1 (

a int not null ,

b int,

c char(10) not null,

d varchar(10) ) engine = innodb charset=utf8mb4;

alter table t1 add index idx_abcd(a,b,c,d);

desc select a,b,c,d from t1 where a= 1 and b = 3 and c = 'd' and d = '4';

1 SIMPLE t1 NULL ref idx_abcd idx_abcd 92 const,const,const,const 1 100.00 Using index

Extra?

using filesort:表示此次查詢使用到了文件排序操作,

說明此次查詢的排序操作 order by group by distinct ...(可能有這些語句)

列子;

?desc select * from city? where countrycode='CHN'? order by? ?population? ;


可以看到,extra出現(xiàn)了using filesort ,這時我們通過添加where條件字段和population字段的聯(lián)合索引看是否能解決此問題;

alter table city add index idx_c_p(countrycode,population);

?desc select * from city? where countrycode='CHN'? order by? ?population? ;


可以看到此問題已經(jīng)解決。

索引應(yīng)用規(guī)范

建立索引的原則(dba運維規(guī)范)

1.建表時一定要有主鍵,一般是個無關(guān)列

2.選擇唯一性索引

3.在聯(lián)合索引中,讓唯一索引(重復(fù)值較少的列)作為最左邊的鍵,可以更快速的來查詢。

4.如果字段過長最好使用前綴索引.

5.索引數(shù)據(jù)不是更多更好

可能產(chǎn)生的問題:

1).磁盤空間增大

2).修改表時,對索引的重構(gòu)和更新和麻煩,越多的索引,會使更新表的時間變慢

3).優(yōu)化器的負擔(dān)很重,會影響優(yōu)化器的選擇

6.刪除不使用的或者很少使用的索引

(percona toolkit).py-duplicate-key-checker? 工具可以查詢到重復(fù)的索引

7.大表加索引,要在業(yè)務(wù)不繁忙的期間操作(8.0以前要鎖表)

8.盡量少在經(jīng)常更新值的列上加索引(update的列,這樣容易索引失效)

9.建索引的原則:

1)必須要有主鍵,如果沒有可以作為主鍵條件的列,創(chuàng)建無關(guān)列。

2)經(jīng)常做為where條件列,order by group by join distinct的條件(業(yè)務(wù):產(chǎn)品功能+用戶行為)

3)最好使用唯一值多的列作為索引條件,如果索引列重復(fù)值較多,可以考慮使用聯(lián)合索引。

4)列值長度較長的索引,我們建議使用前綴索引

5)降低索引條目,一方面不要創(chuàng)建沒有用的索引,不常使用的索引清理,percona toolkit的工具.

6)索引維護要避開業(yè)務(wù)繁忙期

不走索引的情況(開發(fā)規(guī)范)

1 沒有查詢條件,或者查詢條件沒有建立索引

select * from tab; 全表掃描

select * from tab where 1=1 ;

在業(yè)務(wù)庫中,特別是數(shù)據(jù)量比較大的表,

是沒有全表掃描的需求。

對用戶查看是非常痛苦的。

對服務(wù)器來講是毀滅性的。

2.查詢結(jié)果集是原表中的大部分數(shù)據(jù),應(yīng)該是15-30%,

查詢的結(jié)果集,超過了總行數(shù)的25%,優(yōu)化器就覺得沒有必要

走索引。

原因是??? 跟數(shù)據(jù)庫的預(yù)讀能力有關(guān),以及一些參數(shù)有關(guān)。彩蛋??

解決辦法,如果業(yè)務(wù)允許,進行分批次查詢,或者進行分頁查詢。

limit 查詢。

如果不允許,盡量不要把這部分數(shù)據(jù)存儲在mysql,可以放到redis這種類似的

內(nèi)存數(shù)據(jù)庫中.

3。索引本身失效,統(tǒng)計數(shù)據(jù)不真實.

索引和表都有自我維護的能力。

對于表內(nèi)容的變化比較頻繁的情況下,統(tǒng)計信息不準(zhǔn)確,過舊,有可能出現(xiàn)索引失效的情況。

解決辦法:重建索引.

現(xiàn)象:有一條sql語句平時查詢很快,突然很慢,會是什么原因。

表跟新頻繁,統(tǒng)計信息過舊,導(dǎo)致索引失效.

查看表和索引的統(tǒng)計信息:

select * from innodb_table_stats; 表的統(tǒng)計信息

select * from innodb_index_stats; 索引的統(tǒng)計信息

不是實時跟新。

表的實時跟新解決辦法:多刪除點才可以跟新。

所以解決辦法是,重建索引。

4.如果函數(shù)作用在索引上,或者對索引列進行運算,運算包括(+,-,* ,/,!等)

5.隱式轉(zhuǎn)換導(dǎo)致索引失效,這一點應(yīng)當(dāng)引起重視

這里我測試字符串轉(zhuǎn)數(shù)字不會失效,只有數(shù)字轉(zhuǎn)字符串就會失效。

6.<>,not in? 不走索引(輔助索引)(聚簇會走)

單獨的> < in 又可能走索引,也可能不走.

7.like '%_' 百分號在前面不走索引。

如有這種大量的需求可以用mongodb數(shù)據(jù)庫


擴展:優(yōu)化器針對索引的算法

1mysql索引的自優(yōu)化-AHI(索引頁的索引,自適應(yīng)hash索引)

mysql的innodb引擎,能夠創(chuàng)建的只有btree。

ahi作用:自動評估熱的內(nèi)存索引page,生成一個hash索引表,加速

索引讀取的速度。

2.mysql索引的自優(yōu)化 -Change buffer?

insert update delete? 數(shù)據(jù)

對于聚簇索引會立即更新

對于輔助索引,不是實時更新

在innodb內(nèi)存結(jié)構(gòu)中,加入了insert buffer(會話),現(xiàn)版本叫change buffer

change buffer的功能是臨時緩沖輔助索引需要的數(shù)據(jù)更新。

當(dāng)我們需要查詢新insert 的數(shù)據(jù),會在內(nèi)存中進行mege 合并,此時輔助索引就是最新的。

3 ICP 索引下推?

在引擎層再次根據(jù)索引進行過濾,減少磁盤的io。

例如 index(a,b,c) select * from t1 where a= and c=?

?在sql層只走部分索引a,到引擎層再次走索引過濾掉部分c的數(shù)據(jù),

在進行磁盤數(shù)據(jù)讀取,減少了磁盤的io.

所涉及的算法調(diào)優(yōu)的參數(shù):

?select@@optimizer_switch;

|index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on |

如何修改算法參數(shù)?

1).my.cnf?

2).set global??optimizer_switch='batched_key_access=on'

3).hints 在語句里加入? /*+? ?*/? 也就是oracle里面的hint?

4.MRR? muti range read?

mrr = on? mrr_cost_based = on(開啟mrr需要關(guān)閉 mrr_cost_based)

set global??optimizer_switch='mrr_cost_based=off';

默認的輔助索引查詢,會多次回表,產(chǎn)生隨機io。

mrr 緩存一部輔助索引的id,然后進行排序,利用rowid buffer,然后進行一次或者

少次數(shù)的回表,減少回表次數(shù)以及隨機IO;提高服務(wù)器的性能。

輔助索引 回表 >> 聚簇索引?

轉(zhuǎn)換為

輔助索引 > sort id 回表? >聚簇索引?

5.SNLJ? 多表關(guān)聯(lián)優(yōu)化的算法?

a join b on a.xx = b.y y where a.c = b.c?

for each row? in b {

for each row in b{

?a.xx = b.xx send to? client?}

以上例子,可以通過left join 強制驅(qū)動表

6.BNLJ? 多表關(guān)聯(lián)優(yōu)化算法?

a join b on a.xx = b.y y where a.c = b.c

將a表滿足條件的數(shù)據(jù)一次性(使用塊)跟b表比對,并返回,減少了

循環(huán)的次數(shù)。提高了效率。a為驅(qū)動表.

when


7 BKA?

BNLJ的基礎(chǔ)上,也就是把a表的數(shù)據(jù)放到一個塊中,然后在進行排序,然后在跟

b表進行關(guān)聯(lián),可以減少io次數(shù),和隨機io次數(shù)。優(yōu)化非驅(qū)動表的關(guān)聯(lián)輔助索引。

開啟的方式? 開啟:MRR ,在開啟BKA。













?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • mysql執(zhí)行計劃作為分析一條sql的執(zhí)行效率的工具十分有效,通過explain關(guān)鍵字便可查看select語句的具...
    SawyerZhou閱讀 13,153評論 0 11
  • mysql的開源和使用簡單使得其成為目前主流的RDB的主流數(shù)據(jù)庫,但是mysql的效率相比Oracle性能上有很大...
    時之令閱讀 1,116評論 0 3
  • 1、MySQL語法 MySql提供了EXPLAIN語法用來進行查詢分析,在SQL語句前加一個”EXPLAIN”即可...
    chen_chen_chen_閱讀 350評論 0 0
  • 一、分析 數(shù)據(jù)規(guī)模限制查詢速度。在查詢前能否預(yù)先估計究竟要涉及多少行、使用哪些索引、運行時間呢?答案是肯定的,My...
    Djbfifjd閱讀 2,559評論 0 6
  • 引言: 實際項目開發(fā)中,由于我們不知道實際查詢的時候數(shù)據(jù)庫里發(fā)生了什么事情,數(shù)據(jù)庫軟件是怎樣掃描表、怎樣使用索引的...
    chen_chen_chen_閱讀 526評論 0 0

友情鏈接更多精彩內(nèi)容