您好,登錄后才能下訂單哦!
文章是學(xué)習(xí)了林曉斌老師在極客時(shí)間的《mysql實(shí)戰(zhàn)45講》后,根據(jù)自己的理解整理而成的。
當(dāng)我們使用漢語(yǔ)字典查找某個(gè)字時(shí),我們會(huì)先通過(guò)拼音目錄查到那個(gè)字所在的頁(yè)碼,然后直接翻到字典的那一頁(yè),找到我們要查的字,通過(guò)拼音目錄查找比我們拿起字典從頭一頁(yè)一頁(yè)翻找要快的多,數(shù)據(jù)庫(kù)索引也一樣,索引就像書的目錄,通過(guò)索引能極大提高數(shù)據(jù)查詢的效率。
在數(shù)據(jù)庫(kù)中,常見的索引實(shí)現(xiàn)方式有哈希表、有序數(shù)組、搜索樹
二叉搜索樹:一棵空樹,或者是具有下列性質(zhì)的二叉樹: 若它的左子樹不空,則左子樹上所有結(jié)點(diǎn)的值均小于它的根結(jié)點(diǎn)的值; 若它的右子樹不空,則右子樹上所有結(jié)點(diǎn)的值均大于它的根結(jié)點(diǎn)的值; 二叉搜索樹的左、右子樹也分別為二叉搜索樹。
平衡二叉樹:平衡二叉樹是在二叉搜索樹的基礎(chǔ)上引入的,指的是結(jié)點(diǎn)的左子樹和右子樹的深度差不超過(guò)1.
多叉樹:每個(gè)結(jié)點(diǎn)可以有多個(gè)子結(jié)點(diǎn),子節(jié)點(diǎn)的大小從左到右依次遞增。
當(dāng)使用平衡二叉實(shí)現(xiàn)索引時(shí),結(jié)構(gòu)如下圖
從圖中可發(fā)現(xiàn),每次查詢最多需要訪問(wèn)4個(gè)節(jié)點(diǎn)必能得到所要數(shù)據(jù)。例如查詢user2時(shí),查詢過(guò)程為:userA-->userC-->userF-->user2。
所以查詢速度很高,同時(shí),因?yàn)樗阉鳂涞奶匦裕ㄗ笞訕湫∮谟易訕洌?,區(qū)間查詢也很方便。
<br>
如果搜索樹存于內(nèi)存中,與多叉樹相比,二叉樹的搜索速率是最高的,但實(shí)際上數(shù)據(jù)庫(kù)使用的是n叉樹而不是二叉樹。
1、索引不僅存于內(nèi)存,還是寫到磁盤上
2、搜索樹上的每個(gè)結(jié)點(diǎn)在磁盤上表現(xiàn)為一個(gè)數(shù)據(jù)塊
3、多叉樹每個(gè)結(jié)點(diǎn)下可以有多個(gè)子節(jié)點(diǎn),所以存儲(chǔ)相同數(shù)據(jù)量時(shí)多叉樹的樹高比二叉樹小,查詢一個(gè)數(shù)據(jù)需要訪問(wèn)的結(jié)點(diǎn)數(shù)更少,即查詢過(guò)程訪問(wèn)更少的數(shù)據(jù)塊。查詢速度較高。
innodb使用B+樹作為索引結(jié)構(gòu)。
在B+樹中,我們將節(jié)點(diǎn)分為葉子結(jié)點(diǎn)和非葉子結(jié)點(diǎn),非葉子結(jié)點(diǎn)上保存的是索引,而且一個(gè)節(jié)點(diǎn)可以保存多個(gè)索引;數(shù)據(jù)全部存于葉子結(jié)點(diǎn)上,根據(jù)葉子結(jié)點(diǎn)的內(nèi)容不同,innodb索引分為主鍵索引和非主鍵索引。非主鍵索引也稱為二級(jí)索引。
主鍵索引的葉子結(jié)點(diǎn)中保存的數(shù)據(jù)為整行數(shù)據(jù),而非主鍵索引葉子節(jié)點(diǎn)保存的是主鍵的值。
主鍵索引圖
非主鍵索引圖
通過(guò)主鍵索引查詢數(shù)據(jù)時(shí),我們只需查找主鍵索引樹便可以獲取數(shù)據(jù);通過(guò)非主鍵索引查詢數(shù)據(jù)時(shí),我們先通過(guò)非主鍵索引樹查找到主鍵值,然后再在主鍵索引樹搜索一次,這個(gè)過(guò)程稱為回表,也就是說(shuō)非主鍵索引查詢會(huì)比主鍵查詢多搜索一棵樹。所以我們應(yīng)盡可能使用主鍵查詢。
添加新行時(shí),將會(huì)在索引表上添加一條記錄,如果是索引遞增插入時(shí),數(shù)據(jù)都是追加在當(dāng)前最大索引之后,不會(huì)對(duì)樹中其他數(shù)據(jù)造成影響;如果新加入的數(shù)據(jù)的索引值位于節(jié)點(diǎn)的中間,需要挪動(dòng)部分節(jié)點(diǎn)的位置,從而保持索引樹的有序性。
而且,相鄰多個(gè)節(jié)點(diǎn)是存儲(chǔ)在同一個(gè)數(shù)據(jù)頁(yè)上的,此時(shí),如果是在已經(jīng)存儲(chǔ)滿狀態(tài)的數(shù)據(jù)頁(yè)中插入節(jié)點(diǎn),會(huì)申請(qǐng)新的數(shù)據(jù)頁(yè),將部分?jǐn)?shù)據(jù)挪動(dòng)到新的數(shù)據(jù)頁(yè),這個(gè)過(guò)程稱為頁(yè)分裂,頁(yè)分裂除了會(huì)影響性能,還會(huì)降低磁盤空間利用率。不規(guī)則數(shù)據(jù)插入時(shí),會(huì)造成頻繁的頁(yè)分裂。
當(dāng)相鄰兩個(gè)頁(yè)由于刪除了數(shù)據(jù),利用率很低之后,會(huì)將數(shù)據(jù)頁(yè)做合并
所以,一般情況下會(huì)采用遞增主鍵,使新數(shù)據(jù)遞增插入。
使用業(yè)務(wù)邏輯字段做主鍵有什么優(yōu)缺點(diǎn)?
1、業(yè)務(wù)邏輯字段不容易保證索引樹結(jié)點(diǎn)有序插入,這樣寫入成本較高。
2、innodb默認(rèn)使用整數(shù)類型作為主鍵,主鍵長(zhǎng)度較小,二級(jí)索引的葉子結(jié)點(diǎn)中保存的是主鍵值,主鍵長(zhǎng)度越小,二級(jí)索引的葉子結(jié)點(diǎn)占用空間也就越小。
3、當(dāng)然,使用業(yè)務(wù)邏輯字段做主鍵也有好處,可以避免回表,每次只需掃描一次主鍵索引樹即可
綜上,從性能和存儲(chǔ)空間方面考量,自增主鍵往往是更合理的選擇,當(dāng)業(yè)務(wù)場(chǎng)景有且只有一個(gè)索引,而且該索引為唯一索引時(shí),此時(shí)更適合使用業(yè)務(wù)邏輯字段作為主鍵。
因?yàn)閿?shù)據(jù)修改/刪除、頁(yè)分裂等原因,會(huì)導(dǎo)致數(shù)據(jù)頁(yè)空間利用率降低,此時(shí),可以考慮重建索引,將數(shù)據(jù)按順序插入,提高磁盤空間利用率。但重建主鍵索引和普通索引會(huì)有不同影響,重建普通索引,可以達(dá)到提高空間利用率的目的,且不會(huì)對(duì)其他索引造成影響,但如果重建主鍵索引就不合理了,會(huì)影響所有普通索引,性能影響較大,而且無(wú)論是新建/刪除主鍵,都會(huì)重建整張表。這時(shí)我們可以使用alter table T engine=InnoDB這個(gè)語(yǔ)句代替。
查看索引利用率
查看performance_schema.table_io_waits_summary_by_index_usage表
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。