数据库索引怎么实现的
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 數據庫索引怎么實現的
(招銀網絡科技java面經)
?
目錄
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 數據庫索引怎么實現的
1 簡介
2索引是如何工作的
簡介
索引數據結構類型
哈希表
有序數組
搜索樹
索引是怎么提升性能的?
3 優缺點
4 如何合理的建立索引
應該創建索引的
不應該創建索引的
聯合索引是什么?為什么需要注意聯合索引中的順序
5 索引的類型
唯一索引?
主鍵索引
聚集索引
6 局部性原理與磁盤預讀
7 有關文章
1 簡介
數據庫索引,是數據庫管理系統中一個排序的數據結構,以協助快速查詢、更新數據庫表中數據。
在數據之外,數據庫系統還維護著滿足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就可以在這些數據結構上實現高級查找算法。這種數據結構,就是索引。
索引的數據結構和具體存儲引擎的實現有關, 在MySQL中使用較多的索引有Hash索引,B+樹索引等,而我們經常使用的InnoDB存儲引擎的默認索引實現為:B+樹索引.
?
為表設置索引要付出代價的:一是增加了數據庫的存儲空間,二是在插入和修改數據時要花費較多的時間(因為索引也要隨之變動)。
?
上圖展示了一種可能的索引方式。左邊是數據表,一共有兩列七條記錄,最左邊的是數據記錄的物理地址(注意邏輯上相鄰的記錄在磁盤上也并不是一定物理相鄰的)。為了加快Col2的查找,可以維護一個右邊所示的二叉查找樹,每個節點分別包含索引鍵值和一個指向對應數據記錄物理地址的指針,這樣就可以運用二叉查找在O(log2n)的復雜度內獲取到相應數據。
2索引是如何工作的
簡介
首先明白為什么索引會增加速度,DB在執行一條Sql語句的時候,默認的方式是根據搜索條件進行全表掃描,遇到匹配條件的就加入搜索結果集合。如果我們對某一字段增加索引,查詢時就會先去索引列表中一次定位到特定值的行數,大大減少遍歷匹配的行數,所以能明顯增加查詢的速度。那么在任何時候都應該加索引么?
?
使用索引的全部意義就是通過縮小一張表中需要查詢的記錄/行的數目來加快搜索的速度。一個索引是存儲的表中一個特定列的值數據結構(最常見的是B-Tree)。索引是在表的列上創建。所以,要記住的關鍵點是索引包含一個表中列的值,并且這些值存儲在一個數據結構中。請記住記住這一點:索引是一種數據結構 。
索引數據結構類型
三種常見、也比較簡單的數據結構,它們分別是哈希表、有序數組和搜索樹
哈希表
哈希表是一種以鍵-值(key-value)存儲數據的結構,我們只要輸入待查找的值即key,就可以找到其對應的值即Value。哈希的思路很簡單,把值放在數組里,用一個哈希函數把key換算成一個確定的位置,然后把value放在數組的這個位置。
?
不可避免地,多個key值經過哈希函數的換算,會出現同一個值的情況。處理這種情況的一種方法是,拉出一個鏈表。
?
User2和User4根據身份證號算出來的值都是N,但沒關系,后面還跟了一個鏈表。假設,這時候你要查ID_card_n2對應的名字是什么,處理步驟就是:首先,將ID_card_n2通過哈希函數算出N;然后,按順序遍歷,找到User2。
?
圖中四個ID_card_n的值并不是遞增的,這樣做的好處是增加新的User時速度會很快,只需要往后追加。但缺點是,因為不是有序的,所以哈希索引做區間查詢的速度是很慢的。
?
你可以設想下,如果你現在要找身份證號在[ID_card_X, ID_card_Y]這個區間的所有用戶,就必須全部掃描一遍了。
?
哈希表這種結構適用于只有等值查詢的場景,比如Memcached及其他一些NoSQL引擎。
而有序數組在等值查詢和范圍查詢場景中的性能就都非常優秀。還是上面這個根據身份證號查名字的例子,如果我們使用有序數組來實現的話,示意圖如下所示:
有序數組
有序數組在等值查詢和范圍查詢場景中的性能就都非常優秀。還是上面這個根據身份證號查名字的例子,如果我們使用有序數組來實現的話,示意圖如下所示:
?
數組就是按照身份證號遞增的順序保存的。這時候如果你要查ID_card_n2對應的名字,用二分法就可以快速得到,這個時間復雜度是O(log(N))。
?
同時很顯然,這個索引結構支持范圍查詢。你要查身份證號在[ID_card_X, ID_card_Y]區間的User,可以先用二分法找到ID_card_X(如果不存在ID_card_X,就找到大于ID_card_X的第一個User),然后向右遍歷,直到查到第一個大于ID_card_Y的身份證號,退出循環。
?
如果僅僅看查詢效率,有序數組就是最好的數據結構了。但是,在需要更新數據的時候就麻煩了,你往中間插入一個記錄就必須得挪動后面所有的記錄,成本太高。
?
所以,有序數組索引只適用于靜態存儲引擎,比如你要保存的是2017年某個城市的所有人口信息,這類不會再修改的數據。
搜索樹
二叉搜索樹也是課本里的經典數據結構了。還是上面根據身份證號查名字的例子,如果我們用二叉搜索樹來實現的話,示意圖如下所示:
?
B-Tree 是最常用的用于索引的數據結構。因為它們是時間復雜度低, 查找、刪除、插入操作都可以可以在對數時間內完成。另外一個重要原因存儲在B-Tree中的數據是有序的。數據庫管理系統(RDBMS)通常決定索引應該用哪些數據結構。但是,在某些情況下,你在創建索引時可以指定索引要使用的數據結構。
索引是怎么提升性能的?
因為索引基本上是用來存儲列值的數據結構,這使查找這些列值更加快速。如果索引使用最常用的數據結構-B-Tree-那么其中的數據是有序的。有序的列值可以極大的提升性能。下面解釋原因。
?
假設我們在 Employee_Name這一列上創建一個B-Tree索引。這意味著當我們用之前的SQL查找姓名是‘Jesus’的雇員時,不需要再掃描全表。而是用索引查找去查找名字為‘Jesus’的雇員,因為索引已經按照按字母順序排序。索引已經排序意味著查詢一個名字會快很多,因為名字少字母為‘J’的員工都是排列在一起的。另外重要的一點是,索引同時存儲了表中相應行的指針以獲取其他列的數據。
數據庫索引里究竟存的是什么?
你現在已經知道數據庫索引是創建在表的某列上的,并且存儲了這一列的所有值。但是,需要理解的重點是數據庫索引并不存儲這個表中其他列(字段)的值。舉例來說,如果我們在Employee_Name列創建索引,那么列Employee_Age和Employee_Address上的值并不會存儲在這個索引當中。如果我們確實把其他所有字段也存儲在個這個索引中,那就成了拷貝一整張表做為索引-這樣會占用太大的空間而且會十分低效。
索引存儲了指向表中某一行的指針
如果我們在索引里找到某一條記錄作為索引的列的值,如何才能找到這一條記錄的其它值呢?這是很簡單 - 數據庫索引同時存儲了指向表中的相應行的指針。指針是指一塊內存區域, 該內存區域記錄的是對硬盤上記錄的相應行的數據的引用。因此,索引中除了存儲列的值,還存儲著一個指向在行數據的索引。也就是說,索引中的Employee_Name這列的某個值(或者節點)可以描述為 (“Jesus”, 0x82829), 0x82829 就是包含 “Jesus”那行數據在硬盤上的地址。如果沒有這個引用,你就只能訪問到一個單獨的值(“Jesus”),而這樣沒有意義,因為你不能獲取這一行記錄的employee的其他值-例如地址(address)和年齡(age)。
3 優缺點
創建索引可以大大提高系統的性能。
第一,通過創建唯一性索引,可以保證數據庫表中每一行數據的唯一性。
第二,可以大大加快數據的檢索速度,這也是創建索引的最主要的原因。
第三,可以加速表和表之間的連接,特別是在實現數據的參考完整性方面特別有意義。
第四,在使用分組和排序子句進行數據檢索時,同樣可以顯著減少查詢中分組和排序的時間。
第五,通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的性能。
?
也許會有人要問:增加索引有如此多的優點,為什么不對表中的每一個列創建一個索引呢?因為,增加索引也有許多不利的方面。
第一,創建索引和維護索引要耗費時間,這種時間隨著數據量的增加而增加。(時間)
第二,索引需要占物理空間,除了數據表占數據空間之外,每一個索引還要占一定的物理空間,如果要建立聚簇索引,那么需要的空間就會更大。(空間)
第三,當對表中的數據進行增加、刪除和修改的時候,索引也要動態的維護,這樣就降低了數據的維護速度。(維護)
4 如何合理的建立索引
應該創建索引的
索引是建立在數據庫表中的某些列的上面。在創建索引的時候,應該考慮在哪些列上可以創建索引,在哪些列上不能創建索引。一般來說,應該在這些列上創建索引:
1 在經常需要搜索的列上,可以加快搜索的速度;(字段的使用頻率)
2 在作為主鍵的列上,強制該列的唯一性和組織表中數據的排列結構;在經常用在連接的列上,這些列主要是一些外鍵,可以加快連接的速度;
3 在經常需要根據范圍進行搜索的列上創建索引,因為索引已經排序,其指定的范圍是連續的;
4 在經常需要排序的列上創建索引,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;
5在經常使用在WHERE子句中的列上面創建索引,加快條件的判斷速度。
6 在經常用在連接的列上,這些列主要是一些外鍵,可以加快連接的速度;
不應該創建索引的
同樣,對于有些列不應該創建索引。一般來說,不應該創建索引的的這些列具有下列特點:
1于那些在查詢中很少使用或者參考的列不應該創建索引。這是因為,既然這些列很少使用到,因此有索引或者無索引,并不能提高查詢速度。相反,由于增加了索引,反而降低了系統的維護速度和增大了空間需求。
2對于那些只有很少數據值的列也不應該增加索引。這是因為,由于這些列的取值很少,例如人事表的性別列,在查詢的結果中,結果集的數據行占了表中數據行的很大比例,即需要在表中搜索的數據行的比例很大。增加索引,并不能明顯加快檢索速度。
3對于那些定義為text, image和bit數據類型的列不應該增加索引。這是因為,這些列的數據量要么相當大,要么取值很少。
4當修改性能遠遠大于檢索性能時,不應該創建索引。這是因為,修改性能和檢索性能是互相矛盾的。當增加索引時,會提高檢索性能,但是會降低修改性能。當減少索引時,會提高修改性能,降低檢索性能。因此,當修改性能遠遠大于檢索性能時,不應該創建索引。
聯合索引是什么?為什么需要注意聯合索引中的順序
MySQL可以使用多個字段同時建立一個索引,叫做聯合索引.在聯合索引中,如果想要命中索引,需要按照建立索引時的字段順序挨個使用,否則無法命中索引.
具體原因為:
MySQL使用索引時需要索引有序,假設現在建立了"name,age,school"的聯合索引,那么索引的排序為: 先按照name排序,如果name相同,則按照age排序,如果age的值也相等,則按照school進行排序.
當進行查詢時,此時索引僅僅按照name嚴格有序,因此必須首先使用name字段進行等值查詢,之后對于匹配到的列而言,其按照age字段嚴格有序,此時可以使用age字段用做索引查找,,,以此類推.因此在建立聯合索引的時候應該注意索引列的順序,一般情況下,將查詢需求頻繁或者字段選擇性高的列放在前面.此外可以根據特例的查詢或者表結構進行單獨的調整.
5 索引的類型
根據數據庫的功能,可以在數據庫設計器中創建三種索引:唯一索引、主鍵索引和聚集索引。
唯一索引?
唯一索引是不允許其中任何兩行具有相同索引值的索引。
當現有數據中存在重復的鍵值時,大多數數據庫不允許將新創建的唯一索引與表一起保存。數據庫還可能防止添加將在表中創建重復鍵值的新數據。例如,如果在employee表中職員的姓(lname)上創建了唯一索引,則任何兩個員工都不能同姓。
主鍵索引
數據庫表經常有一列或列組合,其值唯一標識表中的每一行。該列稱為表的主鍵。
在數據庫關系圖中為表定義主鍵將自動創建主鍵索引,主鍵索引是唯一索引的特定類型。該索引要求主鍵中的每個值都唯一。當在查詢中使用主鍵索引時,它還允許對數據的快速訪問。
聚集索引
在聚集索引中,表中行的物理順序與鍵值的邏輯(索引)順序相同。一個表只能包含一個聚集索引。
如果某索引不是聚集索引,則表中行的物理順序與鍵值的邏輯順序不匹配。與非聚集索引相比,聚集索引通常提供更快的數據訪問速度。
6 局部性原理與磁盤預讀
由于存儲介質的特性,磁盤本身存取就比主存慢很多,再加上機械運動耗費,磁盤的存取速度往往是主存的幾百分分之一,因此為了提高效率,要盡量減少磁盤I/O。為了達到這個目的,磁盤往往不是嚴格按需讀取,而是每次都會預讀,即使只需要一個字節,磁盤也會從這個位置開始,順序向后讀取一定長度的數據放入內存。這樣做的理論依據是計算機科學中著名的局部性原理:當一個數據被用到時,其附近的數據也通常會馬上被使用。程序運行期間所需要的數據通常比較集中。
由于磁盤順序讀取的效率很高(不需要尋道時間,只需很少的旋轉時間),因此對于具有局部性的程序來說,預讀可以提高I/O效率。
預讀的長度一般為頁(page)的整倍數。頁是計算機管理存儲器的邏輯塊,硬件及操作系統往往將主存和磁盤存儲區分割為連續的大小相等的塊,每個存儲塊稱為一頁(在許多操作系統中,頁得大小通常為4k),主存和磁盤以頁為單位交換數據。當程序要讀取的數據不在主存中時,會觸發一個缺頁異常,此時系統會向磁盤發出讀盤信號,磁盤會找到數據的起始位置并向后連續讀取一頁或幾頁載入內存中,然后異常返回,程序繼續運行。
?
7 有關文章
https://blog.csdn.net/weixin_41563161/article/details/101227932
數據庫基本知識
https://blog.csdn.net/weixin_41563161/article/details/102457643
mysql45深入淺出索引
https://blog.csdn.net/weixin_41563161/article/details/102737347#1.%20什么是索引%3F
?數據庫常見面試知識
https://blog.csdn.net/weixin_41563161/article/details/102966786
mysql45怎么給字符串字段加索引?
https://blog.csdn.net/weixin_41563161/article/details/102859171
mysql45普通索引和唯一索引,應該怎么選擇?
https://blog.csdn.net/weixin_41563161/article/details/102957941
mysql45 MySQL為什么有時候會選錯索引?
https://blog.csdn.net/weixin_41563161/article/details/101228148
mysql基本知識
https://blog.csdn.net/weiliangliang111/article/details/51333169
數據庫索引到底是什么,是怎樣工作的?
?
總結
以上是生活随笔為你收集整理的数据库索引怎么实现的的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: github电脑壁纸_这可能是2020年
- 下一篇: linux cmake编译源码,linu