數據庫(一):索引

關于索引

“索引是一個排序的列表,在這個列表中存儲著索引的值和包含這個值的數據所在行的物理地址,在數據十分龐大的時候,索引可以大大加快查詢的速度,這是因為使用索引后可以不用掃描全表來定位某行的數據,而是先通過索引表找到該行數據對應的物理地址然后訪問相應的數據”

1.使用索引的好處

創建索引可以大大提高系統的性能。

第一,通過創建唯一性索引,可以保證數據庫表中每一行數據的唯一性

第二,可以大大加快數據的檢索速度,這也是創建索引的最主要的原因

第三,可以加速表和表之間的連接,特別是在實現數據的參考完整性方面特別有意義

第四,在使用分組和排序子句進行數據檢索時,同樣可以顯著減少查詢中分組和排序的時間

第五,通過使用索引,可以在查詢的過程中,使用優化隱藏器,提高系統的性能

2.索引的原理

數據在磁盤上是以塊的形式存儲的。為確保對磁盤操作的原子性,訪問數據的時候會一并訪問所有數據塊。磁盤上的這些數據塊與鏈表類似,即它們都包含一個數據段和一個指針,指針指向下一節點(數據塊)的內存地址,而且它們都不需要連續存儲(即邏輯上相鄰的數據塊在物理上可以相隔很遠)

鑒于很多記錄只能做到按一個字段排序,所以要查詢某個未經排序的字段,就需要使用線性查找,即要訪問N/2個數據塊,其中N指的是一個表所涵蓋的所有數據塊。如果該字段是非鍵字段(也就是說,不包含唯一值),那么就要搜索整個表空間,即要訪問全部N個數據塊

然而,對于經過排序的字段,可以使用二分查找,因此只要訪問log2N個數據塊。同樣,對于已經排過序的非鍵字段,只要找到更大的值,也就不用再搜索表中的其他數據塊了。這樣一來,性能就會有實質性的提升

3.什么時候建立索引

索引是建立在數據庫表中的某些列的上面。因此,在創建索引的時候,應該仔細考慮在哪些列上可以創建索引,在哪些列上不能創建索引。一般來說,應該在這些列上創建索引,例如:在經常需要搜索的列上,可以加快搜索的速度;在作為主鍵的列上,強制該列的唯一性和組織表中數據的排列結構;在經常用在連接的列上,這些列主要是一些外鍵,可以加快連接的速度;在經常需要根據范圍進行搜索的列上創建索引,因為索引已經排序,其指定的范圍是連續的;在經常需要排序的列上創建索引,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;在經常使用在WHERE子句中的列上面創建索引,加快條件的判斷速度

同樣,對于有些列不應該創建索引。一般來說,不應該創建索引的這些列具有下列特點:

第一,對于那些在查詢中很少使用或者參考的列不應該創建索引。這是因為既然這些列很少使用到,因此有索引或者無索引,并不能提高查詢速度。相反,由于增加了索引,反而降低了系統維護速度和增大了空間需求。

第二,對于那些只有很少數據值的列也不應該增加索引。這是因為,由于這些列的取值很少,例如人事表的性別列,在查詢的結果中,結果集的數據行占了表中數據行的很大比例,即需要在表中搜索的數據行的比例很大。增加索引,并不能明顯加快檢索速度。

第三,對于那些定義為text,image和bit數據類型的列不應該增加索引。這是因為這些列的數據量要么相當大,要么取值很少。

第四,當修改性能遠遠大于檢索性能時,不應該創建索引。這是因為,修改性能和檢索性能是互相矛盾的。當增加索引時,會提高檢索性能,但是會降低修改性能。當減少索引時,會提高修改性能,降低檢索性能。

索引數據結構

平衡樹

BTree索引

節點存儲數據的索引和指向數據的指針,非葉子節點還包括指向向下磁盤塊的指針

B+Tree索引

非葉子節點只存索引和指向向下的指針,葉子節點存儲索引和指向數據的指針(有的葉子節點還可以存在指向相鄰數據索引的指針)

mysql采用的是B+Tree,原因在于B+Tree非葉子節點只存索引,單個節點的內存占用會小一些,總體占用的內存相對小一些,同時在查詢時由于節點內存相對較小,可以減少加載讀取索引表時的IO次數

索引的優缺點

優勢:可以快速檢索,減少I/O次數,加快檢索速度;根據索引分組和排序,可以加快分組和排序

劣勢:索引本身也是表,因此會占用存儲空間,一般來說,索引表占用的空間的數據表的1.5倍;索引表的維護和創建需要時間成本,這個成本隨著數據量增大而增大;構建索引會降低數據表的修改操作(刪除,添加,修改)的效率,因為在修改數據表的同時還需要修改索引表

索引的分類

主鍵索引:即主索引,根據主鍵建立索引,不允許重復,不允許空值,一般在建表的時候同時建立

唯一索引:用來建立索引的列的值必須是唯一的,允許空值

普通索引:用表中的普通列構建的索引,沒有任何限制

全文索引:用大文本對象的列構建的索引

組合索引:用多個列組合構建的索引,這多個列中的值不允許有空值(在Mysql中遵循“最左前綴原則”,把最常用作為檢索或排序的列放在最左,依次遞減)

索引的實現原理

MySQL支持諸多存儲引擎,而各種存儲引擎對索引的支持也各不相同,因此MySQL數據庫支持多種索引類型,如BTree索引、B+Tree索引,哈希索引、全文索引等等

1.哈希索引

只有memory存儲引擎支持哈希索引,哈希索引引用索引列的值計算該值的hashCode,然后再hashCode相應的位置存儲該值所在行數據的物理位置,因為使用散列算法,因此訪問速度非常快,但是一個值只能對應一個hashCode,而且是散列的分布方式,因此哈希索引不支持范圍查找和排序的功能

2.全文索引

FULLTEXT(全文)索引,僅可用于MyISAM和InnoDB,針對較大的數據,生成全文索引非常的消耗時間和空間。對于文本的大對象,或者較大的CHAR類型的數據,如果使用普通索引,那么匹配文本前幾個字符還是可行的,但是想要匹配文本中間的幾個單詞,那么就要使用LIKE%word%來匹配,這樣需要很長的時間來處理,響應時間會大大增加,這種情況,就可使用時FULLTEXT索引了,在生成FULLTEXT索引時,會為文本生成一份單詞的清單,在索引時及根據這個單詞的清單來索引。FULLTEXT可以在創建表的時候創建,也可以在需要的時候用ALTER或者CREATE INDEX來添加

索引的使用策略

1.什么時候要使用索引?

主鍵自動建立唯一索引

經常作為查詢條件在WHERE或者ORDER BY語句中出現的列要建立索引

作為排序的列要建立索引

查詢中與其他表關聯的字段,外鍵關系建立索引

高并發條件下傾向組合索引

用于聚合函數的列可以建立索引,例如使用了max(column_1)或者count(column_1)時的column_1就需要建立索引

2.什么時候不要使用索引

經常增刪改的列不要建立索引

有大量重復的列不建立索引

表記錄太少不要建立索引,只有當數據庫里已經有了足夠多的測試數據時,它的性能測試結果才有實際參考價值。如果在測試數據庫里只有幾百條數據記錄,它們往往在執行完第一條查詢命令之后就被全部加載到內存里,這將使后續的查詢命令都執行得非常快,不管有沒有使用索引。只有當數據庫里的記錄超過1000條、數據總量也超過了MySQL服務器上的內存總量時,數據庫的性能測試結果才有意義

3.索引失效的情況

在組合索引中不能有列的值為NULL,如果有,那么這一列對組合索引就是無效的

在一個SELECT語句中,索引只能使用一次,如果在WHERE中使用了,那么在ORDER BY中就不要用了

LIKE操作中,’%aaa%‘不會使用索引,也就是索引會失效,但是'aaa%'可以使用索引

在索引的列上使用表達式或者函數會使索引失效,例如 select * from users where YEAR(adddate) < 2007,將在每個行上進行運算,這將導致索引失效而進行全表掃描,因此我們可以改成 select * from users where adddate < '2007-01-01'。其他通配符同樣,也就是說,在查詢條件中使用正則表達式時,只有在搜索模板的第一個字符不是通配符的情況下才能使用索引

在查詢條件中使用不等于,包括<、>和!=會導致索引失效。特別的是如果對主鍵索引使用!=則不會使索引失效,如果對主鍵索引或者整數類型的索引使用<或者>不會使索引失效

在查詢條件中使用IS NULL或者IS NOT NULL會導致索引失效

字符串不加單引號會導致索引失效。更準確的說是類型不一致會導致失效,比如字段email是字符串類型,使用WHERE email = 99999則會導致失效,應該改為WHERE email = '99999'

在查詢條件中使用OR連接多個條件會導致索引失效,除非OR鏈接的每個條件都加上索引,這時應該改為兩次查詢,然后用UNION ALL連接起來

如果排序的字段使用了索引,那么select的字段也要是索引字段,否則索引失效。特別的是如果排序的是主鍵索引則select *也不會導致索引失效

盡量不要包括多列排序,如果一定要,最好為這隊列構建組合索引

索引的優化

1.最左前綴

索引的最左前綴和B+Tree中的“最左前綴原理”有關,舉例來說就是如果設置了組合索引<col1, col2, col3>,那么以下3種情況可以使用索引:col1,<col1, col2>,<col1, col2, col3>,其他的列,比如<col2, col3>, <col1, col3>,col2,col3等等都是不能使用索引的

根據最左前綴原則,我們一般把排序分組頻率最高的列放在最左邊,以此類推

2.帶索引的模糊查詢優化

使用LIKE進行模糊查詢的時候,'%aaa%'不會使用索引,也就是索引會失效。如果是這種情況,只能使用全文索引來進行優化

3.為檢索的條件構建全文索引,然后使用

SELECT * FROM tablename MATCH(index_column) ANGAINST('word')

4.使用短索引

對字符串列進行索引,如果可能應該指定一個前綴長度

例如,有一個CHAR(255)的列,如果在前10個或20個字符內,多數值是唯一的,那么就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節省磁盤空間和I/O操作

聚簇索引和非聚簇索引

主鍵索引往往是聚簇索引,其他索引通常是非聚簇索引

其他

索引優化

1.獨立的列

在進行查詢時,索引列不能是表達式的一部分,也不能是函數的參數,否則無法使用索引

2.多列索引

在需要使用多個列作為條件進行查詢時,使用多列索引比使用多個單列索引性能更好

3.索引列的順序

讓選擇性最強的索引列放在前面

索引的選擇性是指:不重復的索引值和記錄總數的比值。最大值為1,此時每個記錄都有唯一的索引與其對應。選擇性越高,每個記錄的區分度越高,查詢效率也越高

4.前綴索引

對于BLOB、TEXT和VARCHAR類型的列,必須使用前綴索引,只索引開始的部分字符

前綴長度的選取需要根據索引選擇性來確定

5.覆蓋索引

索引包含所有需要查詢的字段的值

具有以下優點:

索引通常遠小于數據行的大小,只讀取索引能大大減少數據訪問量

一些存儲引擎(MyISAM)在內存只緩存索引,而數據依賴于操作系統來緩存。因此,只訪問索引可以不使用系統調用(通常比較費時)

對于InnoDB引擎,若輔助索引能夠覆蓋查詢,則無需訪問主索引

索引的優點

大大減少了服務器需要掃描的數據行數

幫助服務器避免進行排序和分組,以及避免創建臨時表(B+Tree索引是有序的,可以用于ORDER BY和GROUP BY操作)。臨時表主要是在排序和分組過程中創建,不需要排序和分組,也就不需要創建臨時表

將隨機I/O變為順序I/O(B+Tree索引是有序的,會將相鄰的數據都存儲在一起)

索引的使用條件

對于非常小的表,大部分情況下簡單的全表掃描比建立索引更高效

對于中到大型的表,索引就非常高效

但是對于特大型的表,建立和維護索引的代價將會隨之增長。這種情況下,需要用到一種技術可以直接區分出需要查詢的一組數據,而不是一條記錄一條記錄地匹配,例如可以使用分區技術

注意

在根據主索引搜索時,直接找到key所在的節點即可取出數據

在根據輔助索引查找時,則需要先取出主鍵的值,再走一遍主索引

因此在設計表的時候,不建議使用過長的字段作為主鍵,也不建議使用非單調的字段作為主鍵,這樣會造成主索引頻繁分裂

參考資料

為什么數據庫索引查詢會快 - xiaobaxiing - 博客園

深入理解MySQL索引原理和實現——為什么索引可以加速查詢?_tongdanping的博客-CSDN博客_mysql 索引是怎么實現的?

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容

  • 預備知識 B+樹: http://www.lxweimin.com/p/5e0818b7c1ea 索引基礎 索引的...
    SMEB_閱讀 7,094評論 0 6
  • 01概述 索引是幫助MySQL高效獲取數據的排好序的數據結構,用于快速找出某個列中有一特定值的行。 通過上述定義可...
    程序員姜戈閱讀 454評論 0 1
  • 本篇文章我們來了解下數據庫索引,首先什么是數據庫索引?數據庫索引 是為了加快查詢速度對表的字段增加的一種標識。DB...
    shark沒有辣椒閱讀 381評論 0 1
  • MySQL官方對索引的定義為:索引(Index)是幫助MySQL高效獲取數據的數據結構。數據庫查詢是數據庫的最主要...
    邴越閱讀 494評論 0 0
  • 索引類型 索引的建立對于MySQL的高效運行是很重要的,索引可以大大提高MySQL的檢索速度。mysql索引大致可...
    wavefreely閱讀 392評論 0 0