這篇文章主要介紹了如何高效利用索引,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著(zhù)大家一起了解一下。
前言
mysql 相信大部分人都用過(guò),索引肯定也是用過(guò)的,但是你知道如何創(chuàng )建恰當的索引嗎?在數據量小的時(shí)候,不合適的索引對性能并不會(huì )有太大的影響,但是當數據逐漸增大時(shí),性能便會(huì )急劇的下降。
索引基礎
我們都有都知道查字典的步驟,是先在索引頁(yè)中找到這個(gè)字的頁(yè)碼,然后再到對應的頁(yè)碼中查看這個(gè)字的信息。mysql 的索引方法也是和這個(gè)類(lèi)似的,先在索引中找到對應值,然后根據匹配的索引記錄找到對應的數據行。假如有下面的 sql 語(yǔ)句:
select * from student where code='2333'
加入 code 列上建立有索引,mysql 將使用該索引找到值為'2333'的數據行,然后讀取數據行的所有數據返回。
索引類(lèi)型
B-Tree 索引
(不是 B 減樹(shù),就是 B 樹(shù)),絕大多數的索引類(lèi)型都是 B-Tree 的(或者是 B-Tree 的變體),通常我們使用的也是這類(lèi)索引。Mysql 中 MyISAM 存儲引擎使用的是 B-tree,InnoDB 使用的是 B+Tree,B 樹(shù)和 B+樹(shù)的區別自行百度。
樹(shù)結構的索引能夠加快訪(fǎng)問(wèn)數據的速度,存儲引擎不再需要全表掃描來(lái)獲取所需的數據,取而代之的是從樹(shù)的根節點(diǎn)來(lái)進(jìn)行二分搜索,總所周知二分搜索的速度是相當快的,因此我們能夠利用索引來(lái)極大的提高查詢(xún)速度。B-Tree 支持以下幾種類(lèi)型的查詢(xún):
假設再 student 表中僅有:name,age,weight 這樣一個(gè)多列索引,下面的查詢(xún)都能利用到此索引
全值匹配
和索引列中的所有列進(jìn)行匹配。比如查詢(xún)name='abc' and age=12,這里用到了第一列和第二列
匹配最左前列
只是用索引的開(kāi)頭部分,比如查詢(xún)name='ggg'只使用索引的第一列,查詢(xún)name='ggg' and age=12是用索引的第一、二列。
匹配列前綴
也可以只匹配某一列的開(kāi)頭部分,比如查詢(xún)name lik 'g%',查詢(xún) name 以 g 開(kāi)頭的記錄。這里用到了第一列
匹配范圍值
可用于匹配范圍值,比如查詢(xún)name > 'abc' and name < 'bcd'
精確匹配某一列并范圍匹配另外一列
用于匹配多列,比如查詢(xún)name='abc' and age > 12。
總的來(lái)看,可以發(fā)現 B-Tree 索引適用于根據最左前綴的查找,也就是查詢(xún)字段字段順序要和索引字段順序一樣,且以第一個(gè)索引字段開(kāi)頭。比如查詢(xún)name,name and age,name and age and weight都能使用索引,但是查詢(xún)age,age and name不能使用索引。
哈希索引
hash 索引基于 hash 表實(shí)現,只有精確匹配索引所有列才會(huì )生效。MySQL 中只有 Memory 引擎顯示支持哈希索引,同時(shí)也是其默認索引。
InnoDB 無(wú)法創(chuàng )建 hash 索引,但是它有一個(gè)功能叫自適應hash索引,當某些索引值使用非常頻繁時(shí),引擎會(huì )在內存中基于 B-Tree 索引之上再創(chuàng )建一個(gè) hash 索引,這樣就讓 B-Tree 索引也有了一點(diǎn) hash 索引的優(yōu)點(diǎn)。這個(gè)功能是一個(gè)完全自動(dòng)的、內部的行為,也就是無(wú)法手動(dòng)控制或配置。
高性能索引策略
下面是一些常見(jiàn)的索引策略。
獨立的列
這個(gè)很簡(jiǎn)單,如果查詢(xún)中的列不是獨立,便無(wú)法使用索引,比如:
select * from student where age+1=12
即使 age 列有索引,上面的查詢(xún)語(yǔ)句也是無(wú)法利用索引的。
前綴索引和索引選擇性
如果需要索引很長(cháng)的字符串列,直接創(chuàng )建索引,會(huì )讓索引占用更多的空間且速度較慢。一個(gè)優(yōu)化策略是模擬 hash 索引:給列計算一個(gè) hash 值,并在 hash 值列建立索引。
另外一個(gè)辦法就是建立前綴索引。只索引這個(gè)字段開(kāi)始的部分字符,這樣可以極大的解決空間占用,索引建立速度也會(huì )快很多。但是這樣也有如下弊端:
降低了索引選擇性,如果多個(gè)字符串前綴相同便無(wú)法區分,還需要進(jìn)行字符串對比。
不支持order by,group by,原因顯而易見(jiàn),只索引了部分字符,無(wú)法完全區分。
這里的關(guān)鍵是確定索引多少個(gè)字符合適。既要避免長(cháng)度過(guò)大,還要有足夠的索引選擇性。有以下兩種辦法來(lái)幫助確定索引字符數:
索引字段前綴數據分布均勻。也就是以索引字符開(kāi)頭的字符串數目分布均勻,比如索引 name 字段的前 3 個(gè)字符,下面的結果是比較合理(只取排名前 8 的):
如果每一列的數據都比較大,說(shuō)明區分度還不高需要增大索引字符數,直到這個(gè)前綴的選擇性接近完整列的索引性,也就是前面的數據要盡可能的小。
計算完整列的選擇性,并使前綴的選擇性接近于完整列的選擇性。下面語(yǔ)句用戶(hù)計算完整列選擇性:
-- 不同字符串的數目/總的數目就是完整列選擇性 select count(distinct name)/count(*) from person;
下面語(yǔ)句計算索引前 3 個(gè)字段選擇性:
-- 前3個(gè)字符不同的字符串數據/總的數據 select count(distincy left(city,3))/count(*) from person
不斷增大索引字符數目,直到選擇性接近完整列選擇性且繼續增大數據選擇性提升幅度不大的時(shí)候。
創(chuàng )建方法
-- 假設最佳長(cháng)度為4 alter table person add key (name(4));
多列索引
不少人有這樣的誤解,如果一個(gè)查詢(xún)用有多個(gè)字段 ‘a(chǎn)nd'查詢(xún),那么給每個(gè)字段都建立索引不就能最大化提高效率了?事實(shí)并不是如此,mysql 只會(huì )選擇其中一個(gè)字段來(lái)進(jìn)行索引查找。這種情況下應該建立多列索引(又叫聯(lián)合索引),就能利用多個(gè)索引字段了,注意索引列順序要和查詢(xún)的順序一致。
在 5.0 及以上版本中引入了“索引合并”的策略。一定程度上也可以使用多個(gè)單列索引,比如下面的查詢(xún):
-- mysql會(huì )分別使用name和age索引查出數據然后合并 -- 如果使and則查出數據后再對比取交集 select * from person where name = "bob" or age=12
但是不推薦這么做,and 或 or條件過(guò)多會(huì )耗費大量的 CPU 和內存在算法的緩存、排序和合并操作上。
選擇合適的索引列順序
在一個(gè)多列 B-Tree 索引中,索引列的順序意味著(zhù)索引首先是按照最左列進(jìn)行排序,然后是第二列…索引一個(gè)良好的多列索引應該是將選擇性最高的索引放在最前面,然后依次降低,這樣才能更好的利于索引。選擇性計算方發(fā)見(jiàn):前綴索引 小節。
聚族索引
聚族索引不是一種單獨的索引類(lèi)型,而是一種數據存儲方法,具體的細節依賴(lài)其實(shí)現方式。
InnoDB 的聚族索引實(shí)際是在同一個(gè)結構中保存索引值和數據行。因為不能同時(shí)將數據行放在兩個(gè)不同的地方,所以一個(gè)表只能有一個(gè)聚族索引。InnoDB 的聚族索引列為“主鍵列”。
如果沒(méi)有定義主鍵,InnoDB 會(huì )選擇一個(gè)唯一的非空索引代替。如果這樣的索引也沒(méi)有,InnoDB 會(huì )隱式定義一個(gè)主鍵來(lái)作為聚族索引。
聚族索引的主要優(yōu)點(diǎn)是:可以把相關(guān)數據保存在一起,減少磁盤(pán) IO,提高查詢(xún)效率。但是也有缺點(diǎn):
插入順序嚴重依賴(lài)于插入順序。按照主鍵的順序插入是速度最快的方式,否則可能會(huì )導致頁(yè)分裂的問(wèn)題出現,會(huì )占用更多的磁盤(pán)空間,掃描速度也會(huì )變慢??赏ㄟ^(guò)OPTIMIZE TABLE重新組織表。
更新聚族索引列代價(jià)很高,因為索引值變了,行數據也會(huì )跟著(zhù)索引移動(dòng)到新的位置上。
二級索引(非聚族索引)訪(fǎng)問(wèn)行數據需要兩次索引查找,因為二級索引葉子節點(diǎn)存儲的并不是行數據的物理位置,而是行的主鍵值,再通過(guò)主鍵值到聚族索引中取行數據。
覆蓋索引
簡(jiǎn)單來(lái)說(shuō)就是一個(gè)索引覆蓋了需要查詢(xún)的列字段,這樣就不需要再到聚族索引中利用主鍵進(jìn)行二次查找,在一個(gè)二級索引中就能取到所需的數據。
InnoDB 的索引會(huì )在葉子節點(diǎn)中保存索引值,因此如果要查詢(xún)的字段全部包含在某個(gè)索引中,且這個(gè)索引被使用了,那么就能極大的提高查詢(xún)速度。比如如下查詢(xún)語(yǔ)句:
-- name有索引的情況下,直接從索引的葉子節點(diǎn)中取name值返回,無(wú)需二次查找 select name from person where name = 'abc' -- 如果存在`name,age`聚合索引,也會(huì )直接返回數據,無(wú)需二次查找 select name,age from person where name='abc' and age=12
使用索引進(jìn)行排序
mysql 的排序操作也是可以利用索引的,只有當索引的列順序和ORDER BY的順序完全一致,并且所有列的排序方法(正序或者倒序)也一樣時(shí),才能夠使用索引來(lái)進(jìn)行排序。注意:排序的字段可以比對應的索引字段少,但是順序必須一致。如下:
-- 假設有:(name,age,sex)聯(lián)合索引 -- 可使用索引排序 select ... order by name desc,age desc select ... order by name desc,age desc,sex desc -- 不可使用排序 select ... order by name desc,sex desc select ... order by name desc,age asc
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站