馬上就要到國(guó)慶節(jié)了棋枕,好是期待呀。最近一直忙成狗重斑,急需一個(gè)長(zhǎng)假調(diào)整一下自己的心境和狀態(tài)
今天我們要說(shuō)的是索引相關(guān)的知識(shí),這也是數(shù)據(jù)庫(kù)的一個(gè)重點(diǎn)章節(jié)祖很。趕緊準(zhǔn)備好你的筆,跟著我一起勾畫(huà)重點(diǎn)吧假颇,聽(tīng)說(shuō)這里要考哦~~~
索引的作用
- 可以快速根據(jù)索引查找指定的記錄
- 可以根據(jù)索引對(duì)記錄進(jìn)行排序,可以用來(lái)order by 和group by
- 可以將隨機(jī)IO轉(zhuǎn)變?yōu)轫樞騃O,索引是有順序的骨稿,先根據(jù)索引順序查詢,然后根據(jù)查找到的關(guān)鍵值定位記錄
三星系統(tǒng)
- 索引將相關(guān)的記錄放在一起坦冠,獲得一星
- 如果索引中的數(shù)據(jù)順序和查找中的排列順序一致則獲得兩星
- 如果索引中的列包含查詢中全部列則獲得三星
需要注意的是索引并不總是最好的工具,只有當(dāng)索引幫助存儲(chǔ)引擎快速查找到記錄帶來(lái)的好處大于其帶來(lái)的額外工作時(shí)激涤,索引才是有效的
一般情況下:
小表:全表掃描
中表(數(shù)據(jù)量還不是很大):索引優(yōu)化
大表(數(shù)據(jù)量超級(jí)大):高級(jí)技術(shù)比如分區(qū)等
索引類型
mysql中索引類型有很多,索引的實(shí)現(xiàn)方式是通過(guò)存儲(chǔ)引擎實(shí)現(xiàn)的倦踢,而不是服務(wù)器層實(shí)現(xiàn)的
B-TREE索引
一般我們沒(méi)有特別指明索引類型的時(shí)候,說(shuō)的索引應(yīng)該就是B-TREE索引辱挥,它使用B-TREE數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)數(shù)據(jù)的
因?yàn)樗饕怯纱鎯?chǔ)引擎實(shí)現(xiàn)的,所以不同的存儲(chǔ)引擎會(huì)通過(guò)不同的方式來(lái)使用B-TREE索引般贼,MYISAM使用前綴壓縮技術(shù)使得索引更小,同時(shí)采用物理位置引用被索引的行(也就是說(shuō)蕊梧,通過(guò)索引直接就可以找到對(duì)應(yīng)的數(shù)據(jù)行記錄)INNODB則按照原數(shù)據(jù)格式進(jìn)行存儲(chǔ),同時(shí)根據(jù)主鍵引用被所以的行(也就是說(shuō)通過(guò)索引首先會(huì)找到行的主鍵索引肥矢,然后通過(guò)主鍵索引找到具體的行)
B-TREE索引意味著所有存儲(chǔ)的數(shù)據(jù)記錄都是有順序的
根據(jù)表的數(shù)據(jù)大小叠洗,B-TREE樹(shù)層級(jí)深度也將不同,其中每一個(gè)節(jié)點(diǎn)頁(yè)都包含了一個(gè)值以及左邊小于該值的子節(jié)點(diǎn)頁(yè)指針和大于該值的右節(jié)點(diǎn)頁(yè)指針十艾,也就是規(guī)定了該值的上線和下限,而葉子頁(yè)的指針指向的是具體的數(shù)據(jù)忘嫉,而不是其他的節(jié)點(diǎn)頁(yè)
在索引中案腺,順序是非常重要的一個(gè)因素,索引對(duì)多個(gè)值進(jìn)行排序的依據(jù)就是按照create table語(yǔ)句中定義索引時(shí)列的順序來(lái)實(shí)現(xiàn)的
B-TREE索引能使用的類型
全值匹配:所有列進(jìn)行匹配
匹配最左前綴:匹配索引的第一列
匹配列前綴:匹配某一列的值開(kāi)頭的部分
匹配范圍值:索引第一列范圍查找
精確匹配第一列劈榨,范圍匹配另外一列
因?yàn)樗饕龢?shù)中的節(jié)點(diǎn)是有順序的,所以除了按值查找之外拷姿,還可以對(duì)數(shù)據(jù)進(jìn)行order by排序操作,但是使用B-TREE索引也有一定的限制:
如果不是按照索引的最左列開(kāi)始查找跌前,將無(wú)法使用索引
不能跳過(guò)索引中的列
如果查詢中有某個(gè)列的范圍查詢陡舅,則其后面的列都將無(wú)法使用索引進(jìn)行查詢
hash索引
mysql索引是在存儲(chǔ)引擎層實(shí)現(xiàn)的,并沒(méi)有統(tǒng)一的標(biāo)準(zhǔn),不同的存儲(chǔ)引擎實(shí)現(xiàn)的索引方式是不同的
對(duì)于hash索引茎芋,只能精確匹配所有列的值蜈出,因?yàn)榇鎯?chǔ)引擎將會(huì)把生成hash索引的所有列的值用來(lái)構(gòu)建hash code
在mysql中,只有memory引擎顯示支持hash索引铡原,這也是它默認(rèn)的索引類型,memory引擎同時(shí)也是支持非唯一hash索引的燕刻,當(dāng)出現(xiàn)hash沖突時(shí),通過(guò)鏈表的方式解決沖突問(wèn)題
hash索引基于hash表實(shí)現(xiàn)的请唱,在它其中并不保存實(shí)際的值,而是保存hashcode->行的指針的鍵值對(duì)方式
因此使用hash索引能快速的定位到某一行記錄十绑,但是它也存在某些限制:
hash索引只包含hash值與行指針酷勺,而不存儲(chǔ)字段值,所以不能使用索引中的值來(lái)避免讀取行
hash索引數(shù)據(jù)并不是按照索引值順序存儲(chǔ)的鸥印,也就無(wú)法使用排序
hash索引也不支持部分索引列匹配查找,因?yàn)閔ashcode是通過(guò)所有hash列生成出來(lái)的
hash值只支持等值比較查詢,包括=片择,in(),<=>(通過(guò)a <=> null,可以得出a為null的記錄) 不支持任何范圍查詢
訪問(wèn)hash索引的數(shù)據(jù)非匙止埽快,除非有很多hash沖突嘲叔,當(dāng)出現(xiàn)沖突時(shí),存儲(chǔ)引擎只能逐行進(jìn)行查找
如果hash沖突很多時(shí)锰什,維護(hù)起來(lái)代價(jià)也很高,應(yīng)該避免在選擇性比較低的列上建立hash索引
innodb引擎有一個(gè)特殊的功能叫做“自適應(yīng)hash索引”汁胆,當(dāng)innodb注意到某些索引值被頻繁的引用,它會(huì)在內(nèi)存中基于B-TREE索引之上再建立一個(gè)hash索引
如果某些存儲(chǔ)引擎不支持hash索引嫩码,我們需要?jiǎng)?chuàng)建自定義的hash索引,創(chuàng)建一個(gè)偽hash索引列铡恕,通過(guò)CRC32()對(duì)需要hash的列值計(jì)算hash,并在該列上創(chuàng)建索引
對(duì)于hash索引查找没咙,需要在where條件語(yǔ)句中加上hashcode比較和列值比較千劈,這樣是為了解決hash索引帶來(lái)的沖突
select url from t_urls where url_code = crc32(‘http://www.baidu.com’) and url = ‘http://www.baidu.com’;
這里如果發(fā)生了hash沖突,則根據(jù)url列值進(jìn)行查找
上面創(chuàng)建偽hashcode索引列采用的是crc32算法墙牌,生成一個(gè)32位的數(shù)字,但是通常64位數(shù)字hash沖突會(huì)更少喜滨,可以自己定義一個(gè)算法:
select conv(right(md5('http://www.baidu.com'), 16), 16, 10);
如果語(yǔ)句中的索引列不是獨(dú)立的,那么這條語(yǔ)句就不能使用該列索引棒口,也就是說(shuō)索引列不能作為表達(dá)式的一部分或者不能作為函數(shù)的參數(shù)
select acter_id from actor where acter_id +1 = 5;
select ... where to_days(current_date) – to_days(date_col)<= 10
對(duì)于長(zhǎng)度很長(zhǎng)的列,創(chuàng)建索引時(shí)可以采用類似hash索引那樣的无牵,自己建一個(gè)偽hashcode列厂抖,手動(dòng)維護(hù)這個(gè)列,通過(guò)列值計(jì)算該列對(duì)應(yīng)的數(shù)字值并作為hash索引
以u(píng)rl列舉例忱辅,如果直接使用url,則整個(gè)列字段的字符串太長(zhǎng)墙懂,占據(jù)太多空間,我們選擇為url創(chuàng)建一個(gè)url_code,用來(lái)計(jì)算crc32(url)得到的數(shù)字
create table urls {
id int unsigned not null auto_increment,
url varchar(255) not null,
url_code int unsigned not null default 0
primary key(id)
}
在插入或者更新url時(shí)碧库,通過(guò)觸發(fā)器重新計(jì)算url_code的值
delimiter //
create trigger urls_insert_trigger before insert on urls for each row begin
set new.url_code = crc32(new.url);
end;
//
create trigger urls_update_trigger before update on urls for each row begin
set new.url_code = crc32(new.url);
end;
//
delimiter;
通過(guò)偽hashcode列與該列值來(lái)精確查詢某一條記錄
select * from urls where url_code = crc32(‘http://www.baidu.com’) and url = ‘http://www.baidu.com’;
全文索引
全文索引是一種特殊類型的索引,它查找的是文本中的關(guān)鍵字谈为,而不是直接比較索引中的值,它與其他幾種類型的索引匹配方式完全不一樣伞鲫,它存在許多需要注意的細(xì)節(jié):如停用詞、詞干秕脓、復(fù)數(shù)、布爾搜索等吠架,更加類似于搜索引擎要干的事情
前綴索引
通過(guò)比較列選擇性和索引選擇性來(lái)決定前綴的長(zhǎng)度,對(duì)于mysql來(lái)說(shuō)傍药,不允許對(duì)text/blob列全值進(jìn)行索引,但是我們可以通過(guò)在查詢時(shí)指定使用前綴來(lái)優(yōu)化此類查詢拣挪,比如排序時(shí),避免磁盤臨時(shí)表排序
選擇性:不重復(fù)的索引值和數(shù)據(jù)表記錄總數(shù)的比值
select count(*) as count, city as city from t_city group by city order by city desc limit 10;
上面這條語(yǔ)句記錄了每一個(gè)城市出現(xiàn)的重復(fù)次數(shù)
select count(*) as count, left(city, 3) as pref from t_city group by pref order by pref desc limit 10;
還有一種選擇方式:計(jì)算列平均選擇性菠劝,并使前綴選擇性接近列選擇性
select count(distinct city) / count(*) from t_city;
select count(distinct left(city, 3)) / count(*) from t_city
前綴索引的創(chuàng)建方式
alter table sakila.city_demo add key city(7)
這樣就在sakila.city_demo表中創(chuàng)建了一個(gè)city前綴索引睁搭,索引長(zhǎng)度為7個(gè)字符,
使用前綴索引的缺點(diǎn)是:前綴索引不能用來(lái)做order by 和group by操作园骆,也無(wú)法用于作覆蓋掃描
后綴索引
還有一種是“反向索引”,針對(duì)像url這種類型的字符串列而言的遇伞,使用后綴來(lái)進(jìn)行索引效果更佳,但是mysql本身并不支持后綴索引這種方式,所以我們可以通過(guò)將保存的url字符串反向存入數(shù)據(jù)庫(kù)并創(chuàng)建前綴索引的方式來(lái)實(shí)現(xiàn)所謂的后綴索引
選擇合適的索引順序
在B-TREE索引中秋麸,索引列的順序意味著索引從最左列進(jìn)行排序,經(jīng)驗(yàn)法則告訴我們可以將選擇性高的放在前面灸蟆,當(dāng)不需要考慮排序和分組時(shí),將選擇性高的索引列放在前面通常是非常好的
我們需要對(duì)多個(gè)列計(jì)算每個(gè)列對(duì)應(yīng)的選擇性,然后做出決策
select count(distinct staff_id) / count(*) as staff_id_selectivity,
count(distinct custom_id) /count(*) as custom_id_selectivity, count(*) from payment \G;
根據(jù)查詢結(jié)果來(lái)看霎迫,應(yīng)該將custom_id放在索引列staff_id前面
順序的索引會(huì)造成的潛在問(wèn)題:
在高并發(fā)工作時(shí)帘靡,innoDB按主鍵順序插入可能會(huì)引起明顯的間隙鎖爭(zhēng)用
聚簇索引
聚簇索引其實(shí)是一種數(shù)據(jù)結(jié)構(gòu),保存了B-TREE索引和數(shù)據(jù)行描姚,數(shù)據(jù)表中的數(shù)據(jù)記錄都保存在葉子頁(yè)上,但是節(jié)點(diǎn)頁(yè)只包含了索引列
聚簇表示數(shù)據(jù)行與相鄰的鍵值緊湊的存儲(chǔ)在一起,
在innoDB數(shù)據(jù)庫(kù)中筒扒,通過(guò)主鍵索引列來(lái)聚簇?cái)?shù)據(jù)記錄,也就是說(shuō)花墩,在innoDB聚簇索引中,節(jié)點(diǎn)頁(yè)上保存的是行主鍵冰蘑,如果沒(méi)有主鍵列,innoDB會(huì)選擇一個(gè)非空索引代替懂缕,如果也沒(méi)有這樣的索引王凑,innoDB會(huì)創(chuàng)建一個(gè)隱式的主鍵來(lái)進(jìn)行聚簇
在innodb中,沒(méi)有被用來(lái)做聚簇的索引索烹,被稱為是二級(jí)索引,在索引中保存的并不是物理行的位置百姓,而是行記錄的主鍵,需要根據(jù)二級(jí)索引找到行主鍵之后再到聚簇B-TREE中查找指定的行記錄
myisam引擎主鍵與其他索引實(shí)現(xiàn)相同垒拢,主鍵只是一個(gè)名稱為PRIMARY的非空索引。
myisam存儲(chǔ)數(shù)據(jù)就是按照數(shù)據(jù)的插入順序保存的求类,表存儲(chǔ)結(jié)構(gòu)的葉子節(jié)點(diǎn)上保存了當(dāng)前索引列值和物理行所在的位置
innodb通過(guò)B-TREE結(jié)構(gòu)保存數(shù)據(jù)表行的所有列記錄,二級(jí)索引通過(guò)保存主鍵值椿猎,在根據(jù)主鍵值在B-TREE結(jié)構(gòu)中查找物理行數(shù)據(jù)信息
聚集的數(shù)據(jù)有哪些優(yōu)點(diǎn)
- 可以把相關(guān)的數(shù)據(jù)保存在一起惶岭,這樣在查找記錄時(shí)可以從磁盤上讀取少量的頁(yè)就能查到結(jié)果
- 訪問(wèn)數(shù)據(jù)更快按灶,聚簇索引將索引和數(shù)據(jù)都保存在同一個(gè)B-TREE中,因此從聚簇索引獲取數(shù)據(jù)比非聚簇索引獲取數(shù)據(jù)要快
- 使用覆蓋索引掃描的查詢鸯旁,可以直接使用頁(yè)節(jié)點(diǎn)的主鍵值,無(wú)需再根據(jù)主鍵查找數(shù)據(jù)
聚簇索引的缺點(diǎn)
聚簇索引最大限度的提高了I/O密集型應(yīng)用的性能羡亩,但如果數(shù)據(jù)全部都放在內(nèi)存中危融,那么訪問(wèn)的順序就沒(méi)那么重要了 - 插入速度嚴(yán)重依賴于插入順序,按照主鍵的順序插入是加載數(shù)據(jù)到INNODB表中速度最快的方式
- 更新聚簇索引列的代價(jià)很高吉殃,因?yàn)闀?huì)強(qiáng)制每一個(gè)被更新的行移動(dòng)到新的位置
4. 基于聚簇索引的表在插入新行,或者主鍵被更新導(dǎo)致需要移動(dòng)行的時(shí)候蛋勺,可能面臨頁(yè)分裂的問(wèn)題 - 聚簇索引可能導(dǎo)致全表掃描變慢,尤其是行比較稀疏的時(shí)候抱完,或者頁(yè)分裂導(dǎo)致數(shù)據(jù)存儲(chǔ)不連續(xù)的時(shí)候
- 二級(jí)索引可能比想象的大,因?yàn)槎?jí)索引的葉子節(jié)點(diǎn)包含了引用行的主鍵列
- 二級(jí)索引訪問(wèn)需要兩次索引查找碉怔,找主鍵、找數(shù)據(jù)
延遲查詢
對(duì)于某些查詢撮胧,可以通過(guò)延遲查詢來(lái)優(yōu)化
explain select * from products where actor = ‘sean carrey’ and title like ‘%apollo%’\G
其中actor 與title 列建立了索引
這里無(wú)法對(duì)查詢進(jìn)行索引覆蓋,因?yàn)椴樵兊牧袨槿苛星凵叮淮嬖谌魏我粋€(gè)索引可以覆蓋所有列
改為延遲加載,添加索引覆蓋列(actor, title, prod_id)
explain select * from products inner join (
select prod_id from products where actor = ‘sean carrey’ and title like ‘%apollo%’)as t1 on (t1.prod_id = products.prod_id)
上面子查詢采用索引覆蓋墓怀,過(guò)濾prod_id,然后根據(jù)prod_id再到記錄中查找
覆蓋索引
如果一個(gè)索引包含所有需要查詢的字段的值卫键,那么我們就稱之為覆蓋索引
覆蓋索引的好處
- 索引條目通常遠(yuǎn)小于數(shù)據(jù)行大小,所以如果只需要讀取索引永罚,那mysql就會(huì)極大的減少數(shù)據(jù)訪問(wèn)量
- 因?yàn)樗饕前凑樟兄淀樞虼鎯?chǔ)的,所以順序查詢會(huì)比隨機(jī)從磁盤讀取數(shù)據(jù)的I/O要少的多
- 一些存儲(chǔ)引擎如MYISAM在內(nèi)存中只緩存索引呢袱,數(shù)據(jù)則依賴于具體OS來(lái)緩存,因此訪問(wèn)數(shù)據(jù)意味著還需要一次系統(tǒng)調(diào)用羞福,采用覆蓋索引則減少了這樣的系統(tǒng)調(diào)用
- 針對(duì)INNODB的聚簇索引,覆蓋索引可以杜絕二級(jí)索引根據(jù)主鍵值查找數(shù)據(jù)行記錄
覆蓋索引必須要存儲(chǔ)索引列的值卖陵,而hash索引、空間索引泪蔫、全文索引都不存儲(chǔ)索引列的值,所以mysql只能使用b-tree索引做覆蓋索引
當(dāng)發(fā)起一個(gè)索引覆蓋查詢時(shí)撩荣,通過(guò)explain分析語(yǔ)句會(huì)看到extra Using index,這里的extra表示的是檢索數(shù)據(jù)的方式,需要與type進(jìn)行區(qū)分餐曹,type index表示在對(duì)結(jié)果集進(jìn)行排序時(shí)使用到了索引
如果查詢的列沒(méi)有被索引覆蓋敌厘,也就是無(wú)法使用索引覆蓋查詢時(shí),explain查詢分析出來(lái)extra Using where
對(duì)于下面這條語(yǔ)句:
explain select * from products where actor=’seny carrey’ and title like ‘%apollo%’\G
存在兩個(gè)問(wèn)題導(dǎo)致它無(wú)法使用覆蓋索引:
- 沒(méi)有任何一個(gè)索引能夠覆蓋這個(gè)查詢俱两,因?yàn)閺谋碇羞x擇了所有列,而沒(méi)有任何索引覆蓋了所有列
- mysql不能在索引中執(zhí)行l(wèi)ike操作锋华,只是允許使用左前綴匹配的方式和一些簡(jiǎn)單的值比較,上面的查詢語(yǔ)句可以通過(guò)延遲關(guān)聯(lián)來(lái)解決:
select * from product inner join(
select prod_id from product where actor=’seny carrey’ and title like ‘a(chǎn)pollo%’
) as t1 on t1.prod_id = product.prod_id\G
使用索引掃描做排序
排序有兩種方式:直接通過(guò)排序毯焕、按索引順序掃描,如果explain出來(lái)的結(jié)果中的type為index,則表示使用到了索引掃描來(lái)做排序
orderby子句的列順序必須與索引列定義的順序完全一致(也就是說(shuō)按照多個(gè)列進(jìn)行排序婆咸,要么都升序,要么都降序)尚骄,因?yàn)閙ysql是按照索引順序來(lái)組織記錄順序的,而order by 如果打破了這種規(guī)則那么就必須使用文件排序
如果查詢關(guān)聯(lián)多張表倔丈,則只有當(dāng)order by子句引用的字段全部為第一個(gè)表憨闰,才能使用索引做排序
還有一種情況就是如果索引前導(dǎo)列(where語(yǔ)句或者join子句中包含的索引第一列)設(shè)置為常量時(shí)鹉动,就可以使用索引進(jìn)行排序,比如:
(rental_date,inventory_id,customer_id)為一個(gè)組合索引,則語(yǔ)句
select rental_id,staff_id from sakila.rental where rental_date=’2005-05-25’ order by inventory_id,customer_id
可以使用索引進(jìn)行排序泽示,雖然order by 子句不滿足索引的最左前綴要求,也可以用于查詢排序械筛,因?yàn)樗饕谝涣斜辉O(shè)置成為了常量
下面列出不能使用索引做排序的查詢
- 使用兩種不同的排序方向,但是索引列都是正序排列
where rental_date=2005-05-25’ order by inventory_id desc,customer_id asc; - 引用不存在與索引中的列
where rental_date=2005-05-25’ order by inventory_id,staff_id - where與order by中的列無(wú)法組合成索引的最左前綴
where rental_date=’2005-05-25’ order by customer_id - 查詢?cè)谒饕械牡谝涣袨榉秶樵儣l件埋哟,所以mysql無(wú)法使用其他的索引列
where rental_date > ‘2005-05-25’ order by inventory_id,customer_id - 索引列上存在多個(gè)等值條件厌丑,對(duì)于查詢來(lái)說(shuō)其實(shí)就相當(dāng)于范圍查詢
where rental_date = ‘2005-05-25’ and inventory_id in(1,2) order by customer_id
壓縮(前綴壓縮)索引
myisam使用前綴壓縮索引減少索引的大小,從而讓更多的索引能放入內(nèi)存怒竿,默認(rèn)只壓縮字符串,但是也可以配置壓縮整數(shù)
myisam壓縮每個(gè)索引塊的方法是耕驰,先完全保存索引塊的第一個(gè)值,然后將其他值和第一個(gè)值進(jìn)行比較得到相同的前綴的字節(jié)數(shù)和不同的后綴朦肘,把這部分存儲(chǔ)起來(lái)即可,比如:索引塊中第一個(gè)值為perform媒抠,第二個(gè)值為performance,那么第二個(gè)值的前綴壓縮后存儲(chǔ)的是7,ance這樣的形式
前綴索引無(wú)法通過(guò)二分查找只能從頭開(kāi)始掃描趴生,正序的掃描速度還不錯(cuò),但反序就不是很好了
冗余索引和重復(fù)索引
重復(fù)索引苍匆,具有相同類型、按照相同順序的索引叔汁,應(yīng)該避免,發(fā)現(xiàn)后立即刪除
冗余索引据块,(A,B)為索引,再創(chuàng)建索引(A)就是冗余索引瑰钮,因?yàn)锳索引只是AB索引的前綴索引,因此索引(AB)也可以當(dāng)做(A)來(lái)算
默認(rèn)情況下在創(chuàng)建innodb二級(jí)索引時(shí)浪谴,主鍵索引已經(jīng)默認(rèn)添加到該索引上了因苹,例如(A, ID)其中id為主鍵索引
冗余索引必須是相同的類型,其他類型的索引扶檐,比如hash索引或者全文索引頁(yè)不會(huì)是B-TREE索引的冗余索引
索引和鎖
索引可以讓查詢鎖定更少的行,innodb只有在訪問(wèn)行的時(shí)候才會(huì)對(duì)其加鎖款筑,而索引能夠減少innodb訪問(wèn)的行數(shù),從而減少鎖的數(shù)量奈梳,但這只有在存儲(chǔ)引擎層過(guò)濾掉所有不需要的行時(shí)才有效
支持多種過(guò)濾條件
在有更多不同值的列上創(chuàng)建索引的選擇性會(huì)更好,在檢索時(shí)攘须,我們可以將查詢用的多的列加入到索引中,對(duì)于索引前綴列不需要進(jìn)行條件過(guò)濾時(shí)于宙,通過(guò)in指定列值,IN的方式對(duì)查詢檢索是有效的至会,但是對(duì)order by則是無(wú)效的,比如存在(sex,country)這樣的索引奉件,當(dāng)我們需要使用到該索引時(shí),但又不需要對(duì)性別做出限制瓶蚂,那么我們可以通過(guò)and sex in (‘m’,’f’)的方式讓mysql選擇該列索引
避免多個(gè)范圍條件
針對(duì)這兩種查詢語(yǔ)句:
select actor_id from actor where actor_id > 45;
select actor_id from actor where actor_id in (1,4,49);
這兩種查詢語(yǔ)句的執(zhí)行效率是不同的,對(duì)于范圍查詢窃这,mysql是無(wú)法使用范圍列后面的其他索引列了,但是對(duì)于多個(gè)等值條件查詢,則沒(méi)有這個(gè)限制
維護(hù)索引和表
找到并修復(fù)索引表
通過(guò)check table來(lái)檢查是否發(fā)生了表?yè)p壞庇勃,并通過(guò)repair table來(lái)修復(fù)表;但是如果存儲(chǔ)引擎不支持該命令馆铁,也可以通過(guò)alter table 重建表來(lái)達(dá)到修復(fù)目的
alter table innodb_tbl ENGINE=INNODB
更新索引統(tǒng)計(jì)信息
查詢優(yōu)化器通過(guò)兩個(gè)API來(lái)了解存儲(chǔ)引擎的索引值分布锅睛,通過(guò)這兩個(gè)API的結(jié)果來(lái)決定使用哪個(gè)索引進(jìn)行查詢優(yōu)化
records_in_range();傳入兩個(gè)邊界值計(jì)算之間的記錄數(shù)
info();返回各種類型的數(shù)據(jù)包括索引基數(shù)(通過(guò)show index from table)
如果統(tǒng)計(jì)信息不準(zhǔn)確,那么定會(huì)影響到查詢優(yōu)化器的優(yōu)化策略现拒,通過(guò)analyze table重新生成統(tǒng)計(jì)信息
數(shù)據(jù)碎片類型
行碎片:數(shù)據(jù)行被存儲(chǔ)在多個(gè)地方的多個(gè)片段中
行間碎片:邏輯上順序的頁(yè),在磁盤上不是順序的
剩余空間碎片:數(shù)據(jù)頁(yè)中大量的空余空間
通過(guò)optimize table 或者導(dǎo)出再導(dǎo)入的方式來(lái)重新整理數(shù)據(jù)印蔬,對(duì)于不支持該命令的存儲(chǔ)引擎,可以通過(guò)alter table tablename engine=<engine>
來(lái)進(jìn)行優(yōu)化
每種存儲(chǔ)引擎實(shí)現(xiàn)索引統(tǒng)計(jì)信息的方式不同侥猬,所以需要進(jìn)行analyze table的頻率也不同:
- memory引擎根本不存儲(chǔ)索引統(tǒng)計(jì)信息
- myisam引擎將索引統(tǒng)計(jì)信息存儲(chǔ)在磁盤中,analyze table需要進(jìn)行一次全索引掃描來(lái)計(jì)算索引基數(shù)
- 直到mysql5.5鹃锈,innodb也不在磁盤存儲(chǔ)索引統(tǒng)計(jì)信息,而是通過(guò)隨機(jī)的索引訪問(wèn)進(jìn)行評(píng)估仪召,并將估算結(jié)果存在內(nèi)存中
mysql執(zhí)行狀態(tài)
通過(guò)show full processlist來(lái)查看mysql當(dāng)前處在哪一個(gè)狀態(tài)
sleep 線程正等待客戶端發(fā)起查詢請(qǐng)求
locked 在mysql服務(wù)層里,該線程正在等待表鎖
Analyzing and statistics 線程正在搜集存儲(chǔ)引擎的統(tǒng)計(jì)信息扔茅,并生成查詢執(zhí)行計(jì)劃
query 線程正在查詢
Copying to tmp table [on disk],線程正在執(zhí)行查詢,并將結(jié)果復(fù)制到一個(gè)臨時(shí)表中召娜,這種狀態(tài)要么是在group by操作,要么是在文件排序操作玖瘸,如果這個(gè)狀態(tài)后面還有on disk ,則表示mysql正在把一個(gè)內(nèi)存臨時(shí)表放到磁盤
sorting result 線程正在進(jìn)行排序
Sending data 這個(gè)狀態(tài)有多重可能雅倒,有可能是線程之間在進(jìn)行數(shù)據(jù)傳輸,或者正在生成結(jié)果集蔑匣,或者向客戶端返回?cái)?shù)據(jù)