1:Mysql索引是什么mysql索引: 是一種幫助mysql高效的獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)以某種方式引用數(shù)據(jù),,這種結(jié)構(gòu)就是索引,。可簡單理解為排好序的快速查找數(shù)據(jù)結(jié)構(gòu),。如果要查“mysql”這個單詞,,我們肯定需要定位到m字母,然后從下往下找到y(tǒng)字母,,再找到剩下的sql,。 1.1:索引分類 單值索引:一個索引包含1個列 create index idx_XX on table(f1) 一個表可以建多個。 唯一索引: 索引列的值必須唯一,,但允許有空值 create unique index idx_XX on table(f1) 復(fù)合索引: 一個索引包含多個列 如:create index idx_XX on table(f1,f2,,..) 1.2:索引結(jié)構(gòu) BTree Hash索引 full-text全文索引: 1.3:什么情況建立索引 主鍵自動建立唯一索引 頻繁作為查詢條件的字段因該創(chuàng)建索引 查詢中與其他表關(guān)聯(lián)的字段,外鍵關(guān)系建立索引 頻繁更新的字段不適合建立索引 where條件里用不到的字段不建立索引 單鍵/復(fù)合索引的選擇(高并發(fā)下傾向復(fù)合) 查詢中排序的字段因建立索引 查詢中統(tǒng)計或分組字段 1.4:什么情況建不建立索引 頻繁增刪改的表 表記錄太少 數(shù)據(jù)重復(fù)且分布平均的表字段,。(重復(fù)太多索引意義不大) 2:Mysql索引為什么要用B Tree實現(xiàn)2.1:B 樹在數(shù)據(jù)庫索引中的應(yīng)用 目前大部分?jǐn)?shù)據(jù)庫系統(tǒng)及文件系統(tǒng)都采用B-Tree或其變種B Tree作為索引結(jié)構(gòu) 1)在數(shù)據(jù)庫索引的應(yīng)用 在數(shù)據(jù)庫索引的應(yīng)用中,,B 樹按照下列方式進(jìn)行組織 : ①葉結(jié)點的組織方式 。B 樹的查找鍵 是數(shù)據(jù)文件的主鍵 ,且索引是稠密的,。也就是說 ,,葉結(jié)點 中為數(shù)據(jù)文件的第一個記錄設(shè)有一個鍵、指針對 ,,該數(shù)據(jù)文件可以按主鍵排序,,也可以不按主鍵排序 ;數(shù)據(jù)文件按主鍵排序,,且 B 樹是稀疏索引 ,, 在葉結(jié)點中為數(shù)據(jù)文件的每一個塊設(shè)有一個鍵、指針對 ,;數(shù)據(jù)文件不按鍵屬性排序 ,,且該屬性是 B 樹 的查找鍵 , 葉結(jié)點中為數(shù)據(jù)文件里出現(xiàn)的每個屬性K設(shè)有一個鍵 ,、 指針對 ,, 其中指針執(zhí)行排序鍵值為 K的 記錄中的第一個。 ②非葉結(jié)點 的組織方式,。B 樹 中的非葉結(jié)點形成 了葉結(jié)點上的一個多級稀疏索引,。 每個非葉結(jié)點中至少有ceil( m/2 ) 個指針 , 至多有 m 個指針 ,。 2)B 樹索引的插入和刪除 ①在向數(shù)據(jù)庫中插入新的數(shù)據(jù)時,,同時也需要向數(shù)據(jù)庫索引中插入相應(yīng)的索引鍵值 ,則需要向 B 樹 中插入新的鍵值,。即上面我們提到的B-樹插入算法,。 ②當(dāng)從數(shù)據(jù)庫中刪除數(shù)據(jù)時,同時也需要從數(shù)據(jù)庫索引中刪除相應(yīng)的索引鍵值 ,,則需要從 B 樹 中刪 除該鍵值 ,。即B-樹刪除算法 2.2:索引在數(shù)據(jù)庫中的作用 在數(shù)據(jù)庫系統(tǒng)的使用過程當(dāng)中,數(shù)據(jù)的查詢是使用最頻繁的一種數(shù)據(jù)操作,。 最基本的查詢算法當(dāng)然是順序查找(linear search),,遍歷表然后逐行匹配行值是否等于待查找的關(guān)鍵字,其時間復(fù)雜度為O(n),。但時間復(fù)雜度為O(n)的算法規(guī)模小的表,,負(fù)載輕的數(shù)據(jù)庫,也能有好的性能,。 但是數(shù)據(jù)增大的時候,,時間復(fù)雜度為O(n)的算法顯然是糟糕的,性能就很快下降了,。 好在計算機(jī)科學(xué)的發(fā)展提供了很多更優(yōu)秀的查找算法,,例如二分查找(binary search),、二叉樹查找(binary tree search)等。如果稍微分析一下會發(fā)現(xiàn),,每種查找算法都只能應(yīng)用于特定的數(shù)據(jù)結(jié)構(gòu)之上,,例如二分查找要求被檢索數(shù)據(jù)有序,而二叉樹查找只能應(yīng)用于二叉查找樹上,,但是數(shù)據(jù)本身的組織結(jié)構(gòu)不可能完全滿足各種數(shù)據(jù)結(jié)構(gòu)(例如,,理論上不可能同時將兩列都按順序進(jìn)行組織),所以,,在數(shù)據(jù)之外,,數(shù)據(jù)庫系統(tǒng)還維護(hù)著滿足特定查找算法的數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)以某種方式引用(指向)數(shù)據(jù),,這樣就可以在這些數(shù)據(jù)結(jié)構(gòu)上實現(xiàn)高級查找算法,。這種數(shù)據(jù)結(jié)構(gòu),就是索引,。 索引是對數(shù)據(jù)庫表 中一個或多個列的值進(jìn)行排序的結(jié)構(gòu),。與在表 中搜索所有的行相比,索引用指針 指向存儲在表中指定列的數(shù)據(jù)值,,然后根據(jù)指定的次序排列這些指針,有助于更快地獲取信息,。通常情 況下 ,,只有當(dāng)經(jīng)常查詢索引列中的數(shù)據(jù)時 ,才需要在表上創(chuàng)建索引,。索引將占用磁盤空間,,并且影響數(shù) 據(jù)更新的速度。但是在多數(shù)情況下 ,,索引所帶來的數(shù)據(jù)檢索速度優(yōu)勢大大超過它的不足之處,。 2.3:為什么使用B-Tree(B Tree) 1.文件很大,不可能全部存儲在內(nèi)存中,,故要存儲到磁盤上 2.索引的結(jié)構(gòu)組織要盡量減少查找過程中磁盤I/O的存取次數(shù)(為什么使用B-/ Tree,,還跟磁盤存取原理有關(guān)。) 3.局部性原理與磁盤預(yù)讀,,預(yù)讀的長度一般為頁(page)的整倍數(shù),,(在許多操作系統(tǒng)中,頁得大小通常為4k) 4.數(shù)據(jù)庫系統(tǒng)巧妙利用了磁盤預(yù)讀原理,,將一個節(jié)點的大小設(shè)為等于一個頁,,這樣每個節(jié)點只需要一次I/O就可以完全載入,(由于節(jié)點中有兩個數(shù)組,,所以地址連續(xù)),。而紅黑樹這種結(jié)構(gòu),h明顯要深的多。由于邏輯上很近的節(jié)點(父子)物理上可能很遠(yuǎn),,無法利用局部性 二叉查找樹進(jìn)化品種的紅黑樹等數(shù)據(jù)結(jié)構(gòu)也可以用來實現(xiàn)索引,,但是文件系統(tǒng)及數(shù)據(jù)庫系統(tǒng)普遍采用B-/ Tree作為索引結(jié)構(gòu)。 一般來說,,索引本身也很大,,不可能全部存儲在內(nèi)存中,因此索引往往以索引文件的形式存儲的磁盤上,。這樣的話,,索引查找過程中就要產(chǎn)生磁盤I/O消耗,相對于內(nèi)存存取,,I/O存取的消耗要高幾個數(shù)量級,,所以評價一個數(shù)據(jù)結(jié)構(gòu)作為索引的優(yōu)劣最重要的指標(biāo)就是在查找過程中磁盤I/O操作次數(shù)的漸進(jìn)復(fù)雜度。換句話說,,索引的結(jié)構(gòu)組織要盡量減少查找過程中磁盤I/O的存取次數(shù),。為什么使用B-/ Tree,還跟磁盤存取原理有關(guān),。 局部性原理與磁盤預(yù)讀 由于存儲介質(zhì)的特性,,磁盤本身存取就比主存慢很多,再加上機(jī)械運動耗費,,磁盤的存取速度往往是主存的幾百分分之一,,因此為了提高效率,要盡量減少磁盤I/O,。為了達(dá)到這個目的,,磁盤往往不是嚴(yán)格按需讀取,而是每次都會預(yù)讀,,即使只需要一個字節(jié),,磁盤也會從這個位置開始,順序向后讀取一定長度的數(shù)據(jù)放入內(nèi)存,。這樣做的理論依據(jù)是計算機(jī)科學(xué)中著名的局部性原理: 當(dāng)一個數(shù)據(jù)被用到時,,其附近的數(shù)據(jù)也通常會馬上被使用。 程序運行期間所需要的數(shù)據(jù)通常比較集中,。 由于磁盤順序讀取的效率很高(不需要尋道時間,,只需很少的旋轉(zhuǎn)時間),因此對于具有局部性的程序來說,,預(yù)讀可以提高I/O效率,。 預(yù)讀的長度一般為頁(page)的整倍數(shù)。頁是計算機(jī)管理存儲器的邏輯塊,,硬件及操作系統(tǒng)往往將主存和磁盤存儲區(qū)分割為連續(xù)的大小相等的塊,,每個存儲塊稱為一頁(在許多操作系統(tǒng)中,,頁得大小通常為4k),主存和磁盤以頁為單位交換數(shù)據(jù),。當(dāng)程序要讀取的數(shù)據(jù)不在主存中時,,會觸發(fā)一個缺頁異常,此時系統(tǒng)會向磁盤發(fā)出讀盤信號,,磁盤會找到數(shù)據(jù)的起始位置并向后連續(xù)讀取一頁或幾頁載入內(nèi)存中,,然后異常返回,程序繼續(xù)運行,。 我們上面分析B-/ Tree檢索一次最多需要訪問節(jié)點: h = 數(shù)據(jù)庫系統(tǒng)巧妙利用了磁盤預(yù)讀原理,,將一個節(jié)點的大小設(shè)為等于一個頁,這樣每個節(jié)點只需要一次I/O就可以完全載入,。為了達(dá)到這個目的,,在實際實現(xiàn)B- Tree還需要使用如下技巧: 每次新建節(jié)點時,直接申請一個頁的空間,,這樣就保證一個節(jié)點物理上也存儲在一個頁里,,加之計算機(jī)存儲分配都是按頁對齊的,就實現(xiàn)了一個node只需一次I/O,。 B-Tree中一次檢索最多需要h-1次I/O(根節(jié)點常駐內(nèi)存),,漸進(jìn)復(fù)雜度為O(h)=O(logmN)。一般實際應(yīng)用中,,m是非常大的數(shù)字,,通常超過100,因此h非常?。ㄍǔ2怀^3),。 綜上所述,,用B-Tree作為索引結(jié)構(gòu)效率是非常高的,。 而紅黑樹這種結(jié)構(gòu),h明顯要深的多,。由于邏輯上很近的節(jié)點(父子)物理上可能很遠(yuǎn),,無法利用局部性,所以紅黑樹的I/O漸進(jìn)復(fù)雜度也為O(h),,效率明顯比B-Tree差很多,。 3:Mysql索引如何實現(xiàn)1)主鍵索引: MyISAM引擎使用B Tree作為索引結(jié)構(gòu),葉節(jié)點的data域存放的是數(shù)據(jù)記錄的地址,。下圖是MyISAM主鍵索引的原理圖: (圖myisam1) 這里設(shè)表一共有三列,,假設(shè)我們以Col1為主鍵,圖myisam1是一個MyISAM表的主索引(Primary key)示意,??梢钥闯鯩yISAM的索引文件僅僅保存數(shù)據(jù)記錄的地址,。 2)輔助索引(Secondary key) 在MyISAM中,主索引和輔助索引(Secondary key)在結(jié)構(gòu)上沒有任何區(qū)別,,只是主索引要求key是唯一的,,而輔助索引的key可以重復(fù)。如果我們在Col2上建立一個輔助索引,,則此索引的結(jié)構(gòu)如下圖所示: 同樣也是一顆B Tree,,data域保存數(shù)據(jù)記錄的地址。因此,,MyISAM中索引檢索的算法為首先按照B Tree搜索算法搜索索引,,如果指定的Key存在,則取出其data域的值,,然后以data域的值為地址,,讀取相應(yīng)數(shù)據(jù)記錄。 MyISAM的索引方式也叫做“非聚集”的,,之所以這么稱呼是為了與InnoDB的聚集索引區(qū)分,。 4:InnoDB索引實現(xiàn)雖然InnoDB也使用B Tree作為索引結(jié)構(gòu),但具體實現(xiàn)方式卻與MyISAM截然不同,。 第一個重大區(qū)別是InnoDB的數(shù)據(jù)文件本身就是索引文件,。從上文知道,MyISAM索引文件和數(shù)據(jù)文件是分離的,,索引文件僅保存數(shù)據(jù)記錄的地址,。而在InnoDB中,表數(shù)據(jù)文件本身就是按B Tree組織的一個索引結(jié)構(gòu),,這棵樹的葉節(jié)點data域保存了完整的數(shù)據(jù)記錄,。這個索引的key是數(shù)據(jù)表的主鍵,因此InnoDB表數(shù)據(jù)文件本身就是主索引,。 上圖是InnoDB主索引(同時也是數(shù)據(jù)文件)的示意圖,,可以看到葉節(jié)點包含了完整的數(shù)據(jù)記錄。這種索引叫做聚集索引,。因為InnoDB的數(shù)據(jù)文件本身要按主鍵聚集,,所以InnoDB要求表必須有主鍵(MyISAM可以沒有),如果沒有顯式指定,,則MySQL系統(tǒng)會自動選擇一個可以唯一標(biāo)識數(shù)據(jù)記錄的列作為主鍵,,如果不存在這種列,則MySQL自動為InnoDB表生成一個隱含字段作為主鍵,,這個字段長度為6個字節(jié),,類型為長整形。 第二個與MyISAM索引的不同是InnoDB的輔助索引data域存儲相應(yīng)記錄主鍵的值而不是地址,。換句話說,,InnoDB的所有輔助索引都引用主鍵作為data域,。例如,下圖為定義在Col3上的一個輔助索引: 這里以英文字符的ASCII碼作為比較準(zhǔn)則,。聚集索引這種實現(xiàn)方式使得按主鍵的搜索十分高效,,但是輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵,然后用主鍵到主索引中檢索獲得記錄,。 了解不同存儲引擎的索引實現(xiàn)方式對于正確使用和優(yōu)化索引都非常有幫助,,例如知道了InnoDB的索引實現(xiàn)后,就很容易明白為什么不建議使用過長的字段作為主鍵,,因為所有輔助索引都引用主索引,,過長的主索引會令輔助索引變得過大。再例如,,用非單調(diào)的字段作為主鍵在InnoDB中不是個好主意,,因為InnoDB數(shù)據(jù)文件本身是一顆B Tree,非單調(diào)的主鍵會造成在插入新記錄時數(shù)據(jù)文件為了維持B Tree的特性而頻繁的分裂調(diào)整,,十分低效,,而使用自增字段作為主鍵則是一個很好的選擇。 4:程序員進(jìn)階方法以上是我總結(jié)出的Mysql索引底層數(shù)據(jù)結(jié)構(gòu)剖析,,但在此,,我還想給大家一種學(xué)習(xí)方法,讓大家不單單在理論有所收獲,,還能在工作實踐中收獲更多,。我推薦的這種方法。
在此我向大家推薦一個交流學(xué)習(xí)群:575745314 (加群可以學(xué)習(xí)程序員進(jìn)階方法) 里面會分享一些資深架構(gòu)師錄制的視頻錄像:有Spring,,MyBatis,,Netty源碼分析,高并發(fā),、高性能,、分布式、微服務(wù)架構(gòu)的原理,,JVM性能優(yōu)化這些成為架構(gòu)師必備的知識體系,。還能領(lǐng)取免費的學(xué)習(xí)資源,目前受益良多 以下是程序員的進(jìn)階方法: 一,、源碼分析 二,、分布式架構(gòu) 三、微服務(wù) 四,、性能優(yōu)化 五,、團(tuán)隊協(xié)作 六:電商實戰(zhàn) 七:并發(fā)編程 |
|