數據庫索引問題

簡單談談數據庫索引

 

  最近筆試面試特別多的都問到了數據庫索引,因爲以前並無單獨作系統的複習,致使許多關於索引的知識點記憶的很模糊,今天整理下相關筆記(並無深挖,對於初學者仍是能夠看看的),僅供參考。mysql

什麼是索引

  數據庫索引比如是一本書前面的目錄,能加快數據庫的查詢速度。面試

例如這樣一個查詢:select * from table1 where id=44。若是沒有索引,必須遍歷整個表,直到ID等於44的這一行被找到爲止;有了索引以後(必須是在ID這一列上創建的索引),直接在索引裏面找 44(也就是在ID這一列找),就能夠得知這一行的位置,也就是找到了這一行。可見,索引是用來定位的。sql

索引分爲聚簇索引和非聚簇索引兩種,聚簇索引 是按照數據存放的物理位置爲順序的,而非聚簇索引就不同了;聚簇索引能提升多行檢索的速度,而非聚簇索引對於單行的檢索很快。數據庫

  創建索引的目的是加快對錶中記錄的查找或排序。數據結構

  爲表設置索引要付出代價的:一是增長了數據庫的存儲空間,二是在插入和修改數據時要花費較多的時間(由於索引也要隨之變更)。數據庫設計

爲何要建立索引

建立索引能夠大大提升系統的性能。post

第一,經過建立惟一性索引,能夠保證數據庫表中每一行數據的惟一性。性能

第二,能夠大大加快數據的檢索速度,這也是建立索引的最主要的緣由。大數據

第三,能夠加速表和表之間的鏈接,特別是在實現數據的參考完整性方面特別有意義。優化

第四,在使用分組和排序子句進行數據檢索時,一樣能夠顯著減小查詢中分組和排序的時間。

第五,經過使用索引,能夠在查詢的過程當中,使用優化隱藏器,提升系統的性能。

也許會有人要問:增長索引有如此多的優勢,爲何不對錶中的每個列建立一個索引呢?由於,增長索引也有許多不利的方面。

第一,建立索引和維護索引要耗費時間,這種時間隨着數據量的增長而增長。

第二,索引須要佔物理空間,除了數據表佔數據空間以外,每個索引還要佔必定的物理空間,若是要創建聚簇索引,那麼須要的空間就會更大。

第三,當對錶中的數據進行增長、刪除和修改的時候,索引也要動態的維護,這樣就下降了數據的維護速度。

在哪建索引

  索引是創建在數據庫表中的某些列的上面。在建立索引的時候,應該考慮在哪些列上能夠建立索引,在哪些列上不能建立索引。通常來講,應該在這些列上建立索引:

1.在常常須要搜索的列上,能夠加快搜索的速度;

2.在做爲主鍵的列上,強制該列的惟一性和組織表中數據的排列結構;

3.在常常用在鏈接的列上,這些列主要是一些外鍵,能夠加快鏈接的速度;在常常須要根據範圍進行搜索的列上建立索引,由於索引已經排序,其指定的範圍是連續的;

4.在常常須要排序的列上建立索引,由於索引已經排序,這樣查詢能夠利用索引的排序,加快排序查詢時間;

5.在常用在WHERE子句中的列上面建立索引,加快條件的判斷速度。

一樣,對於有些列不該該建立索引。通常來講,不該該建立索引的的這些列具備下列特色:

第一,對於那些在查詢中不多使用或者參考的列不該該建立索引。這是由於,既然這些列不多使用到,所以有索引或者無索引,並不能提升查詢速度。相反,因爲增長了索引,反而下降了系統的維護速度和增大了空間需求。

第二,對於那些只有不多數據值的列也不該該增長索引。這是由於,因爲這些列的取值不多,例如人事表的性別列,在查詢的結果中,結果集的數據行佔了表中數據行的很大比例,即須要在表中搜索的數據行的比例很大。增長索引,並不能明顯加快檢索速度。

第三,對於那些定義爲text, image和bit數據類型的列不該該增長索引。這是由於,這些列的數據量要麼至關大,要麼取值不多,不利於使用索引。

第四,當修改性能遠遠大於檢索性能時,不該該建立索引。這是由於,修改性能和檢索性能是互相矛盾的。當增長索引時,會提升檢索性能,可是會下降修改性能。當減小索引時,會提升修改性能,下降檢索性能。所以,當修改操做遠遠多於檢索操做時,不該該建立索引。

索引的數據結構

  B-tree,B是balance,通常用於數據庫的索引。使用B-tree結構能夠顯著減小定位記錄時所經歷的中間過程,從而加快存取速度。而B+tree是B-tree的一個變種,大名鼎鼎的MySQL就廣泛使用B+tree實現其索引結構。

  插入(insert)操做:插入一個元素時,首先在B-tree中是否存在,若是不存在,即在葉子結點處結束,而後在葉子結點中插入該新的元素,注意:若是葉子結點空間足夠,這裏須要向右移動該葉子結點中大於新插入關鍵字的元素,若是空間滿了以至沒有足夠的空間去添加新的元素,則將該結點進行「分裂」,將一半數量的關鍵字元素分裂到新的其相鄰右結點中,中間關鍵字元素上移到父結點中(固然,若是父結點空間滿了,也一樣須要「分裂」操做),並且當結點中關鍵元素向右移動了,相關的指針也須要向右移。若是在根結點插入新元素,空間滿了,則進行分裂操做,這樣原來的根結點中的中間關鍵字元素向上移動到新的根結點中,所以致使樹的高度增長一層。

  刪除(delete)操做:首先查找B-tree中需刪除的元素,若是該元素在B-tree中存在,則將該元素在其結點中進行刪除,若是刪除該元素後,首先判斷該元素是否有左右孩子結點,若是有,則上移孩子結點中的某相近元素到父節點中,而後是移動以後的狀況;若是沒有,直接刪除後,移動以後的狀況.。刪除元素,移動相應元素以後,若是某結點中元素數目小於ceil(m/2)-1,則須要看其某相鄰兄弟結點是否豐滿(結點中元素個數大於ceil(m/2)-1),若是豐滿,則向父節點借一個元素來知足條件;若是其相鄰兄弟都剛脫貧,即借了以後其結點數目小於ceil(m/2)-1,則該結點與其相鄰的某一兄弟結點進行「合併」成一個結點,以此來知足條件。

下面結合例子詳細講解mysql中索引的使用

索引是快速搜索的關鍵。MySQL索引的創建對於MySQL的高效運行是很重要的。下面介紹幾種常見的MySQL索引類型。在數據庫表中,對字段創建索引能夠大大提升查詢速度。假如咱們建立了一個 mytable表:CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL ); 咱們隨機向裏面插入了10000條記錄,其中有一條:5555, admin。在查找username="admin"的記錄 SELECT * FROM mytable WHERE username='admin';時,若是在username上已經創建了索引,MySQL無須任何掃描,即準確可找到該記錄。相反,MySQL會掃描全部記錄,即要查詢10000條記錄。索引分單列索引和組合索引。單列索引,即一個索引只包含單個列,一個表能夠有多個單列索引,但這不是組合索引。組合索引,即一個索包含多個列。MySQL索引類型包括:(1)普通索引這是最基本的索引,它沒有任何限制。它有如下幾種建立方式:◆建立索引CREATE INDEX indexName ON mytable(username(length)); 若是是CHAR,VARCHAR類型,length能夠小於字段實際長度;若是是BLOB和TEXT類型,必須指定 length,下同。◆修改表結構ALTER mytable ADD INDEX [indexName] ON (username(length))◆建立表的時候直接指定CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, INDEX [indexName] (username(length)) ); 刪除索引的語法:DROP INDEX [indexName] ON mytable;(2)惟一索引它與前面的普通索引相似,不一樣的就是:索引列的值必須惟一,但容許有空值。若是是組合索引,則列值的組合必須惟一。它有如下幾種建立方式:◆建立索引CREATE UNIQUE INDEX indexName ON mytable(username(length))◆修改表結構ALTER mytable ADD UNIQUE [indexName] ON (username(length))◆建立表的時候直接指定CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, UNIQUE [indexName] (username(length)) ); (3)主鍵索引它是一種特殊的惟一索引,不容許有空值。通常是在建表的時候同時建立主鍵索引:CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, PRIMARY KEY(ID) ); 固然也能夠用 ALTER 命令。記住:一個表只能有一個主鍵。(4)組合索引爲了形象地對比單列索引和組合索引,爲表添加多個字段:CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, city VARCHAR(50) NOT NULL, age INT NOT NULL ); 爲了進一步榨取MySQL的效率,就要考慮創建組合索引。就是將 name, city, age建到一個索引裏:ALTER TABLE mytable ADD INDEX name_city_age (name(10),city,age); 建表時,usernname長度爲 16,這裏用 10。這是由於通常狀況下名字的長度不會超過10,這樣會加速索引查詢速度,還會減小索引文件的大小,提升INSERT的更新速度。若是分別在 usernname,city,age上創建單列索引,讓該表有3個單列索引,查詢時和上述的組合索引效率也會大不同,遠遠低於咱們的組合索引。雖然此時有了三個索引,但MySQL只能用到其中的那個它認爲彷佛是最有效率的單列索引。創建這樣的組合索引,實際上是至關於分別創建了下面三組組合索引:usernname,city,age usernname,city usernname 爲何沒有 city,age這樣的組合索引呢?這是由於MySQL組合索引「最左前綴」的結果。簡單的理解就是隻從最左面的開始組合。並非只要包含這三列的查詢都會用到該組合索引,下面的幾個SQL就會用到這個組合索引:SELECT * FROM mytable WHREE username="admin" AND city="鄭州" SELECT * FROM mytable WHREE username="admin" 而下面幾個則不會用到:SELECT * FROM mytable WHREE age=20 AND city="鄭州" SELECT * FROM mytable WHREE city="鄭州"(5)創建索引的時機到這裏咱們已經學會了創建索引,那麼咱們須要在什麼狀況下創建索引呢?通常來講,在WHERE和JOIN中出現的列須要創建索引,但也不徹底如此,由於MySQL只對<,<=,=,>,>=,BETWEEN,IN,以及某些時候的LIKE纔會使用索引。例如:SELECT t.Name FROM mytable t LEFT JOIN mytable m ON t.Name=m.username WHERE m.age=20 AND m.city='鄭州' 此時就須要對city和age創建索引,因爲mytable表的userame也出如今了JOIN子句中,也有對它創建索引的必要。剛纔提到只有某些時候的LIKE才需創建索引。由於在以通配符%和_開頭做查詢時,MySQL不會使用索引。例以下句會使用索引:SELECT * FROM mytable WHERE username like'admin%' 而下句就不會使用:SELECT * FROM mytable WHEREt Name like'%admin' 所以,在使用LIKE時應注意以上的區別。(6)索引的不足之處上面都在說使用索引的好處,但過多的使用索引將會形成濫用。所以索引也會有它的缺點:◆雖然索引大大提升了查詢速度,同時卻會下降更新表的速度,如對錶進行INSERT、UPDATE和DELETE。由於更新表時,MySQL不只要保存數據,還要保存一下索引文件。◆創建索引會佔用磁盤空間的索引文件。通常狀況這個問題不太嚴重,但若是你在一個大表上建立了多種組合索引,索引文件的會膨脹很快。索引只是提升效率的一個因素,若是你的MySQL有大數據量的表,就須要花時間研究創建最優秀的索引,或優化查詢語句。(7)使用索引的注意事項使用索引時,有如下一些技巧和注意事項:◆索引不會包含有NULL值的列只要列中包含有NULL值都將不會被包含在索引中,複合索引中只要有一列含有NULL值,那麼這一列對於此複合索引就是無效的。因此咱們在數據庫設計時不要讓字段的默認值爲NULL。◆使用短索引對串列進行索引,若是可能應該指定一個前綴長度。例如,若是有一個CHAR(255)的列,若是在前10個或20個字符內,多數值是唯一的,那麼就不要對整個列進行索引。短索引不只能夠提升查詢速度並且能夠節省磁盤空間和I/O操做。◆索引列排序MySQL查詢只使用一個索引,所以若是where子句中已經使用了索引的話,那麼order by中的列是不會使用索引的。所以數據庫默認排序能夠符合要求的狀況下不要使用排序操做;儘可能不要包含多個列的排序,若是須要最好給這些列建立複合索引。◆like語句操做通常狀況下不鼓勵使用like操做,若是非使用不可,如何使用也是一個問題。like 「%aaa%」 不會使用索引而like 「aaa%」可使用索引。◆不要在列上進行運算select * from users where YEAR(adddate)<2007; 將在每一個行上進行運算,這將致使索引失效而進行全表掃描,所以咱們能夠改爲select * from users where adddate<‘2007-01-01’; ◆不使用NOT IN和<>操做以上,就對其中MySQL索引類型進行了介紹。

相關文章
相關標籤/搜索