mysql索引介紹
阿新 • • 發佈:2017-11-28
lob exp tab 系統 存取 io操作 內存 html 失效 0.索引的概念
索引是一種特殊的文件(InnoDB數據表上的索引是表空間的一個組成部分),它們包含著對數據表裏所有記錄的引用指針。好比是一本書前面的目錄,能加快數據庫的查詢速度。
無論是Myisam和Innodb引擎,如果在建表的時候沒有顯示的定義一行主鍵列的話,他內部都會自動創建一個隱藏的主鍵索引;
1.索引的優點:
a.大大減少服務器需要掃描的數據量
b.幫助服務器避免排序和臨時表
c.將隨機IO變為順序IO
2.“三星 ”系統:
索引將相關的記錄放在一起,獲得一星
索引中的數據順序和查找中的排列順序一直,再獲得一星
索引中的列涵蓋了查詢中需要的全部列,再獲得一星
3.按照實現方式來劃分的索引類型
哈希索引:基於哈希表實現,只有精確匹配索引所有列的查詢才有效,只有Memory引擎實現
空間數據索引(R-Tree ),只有MyISAM引擎實現
全文索引:分詞後查找關鍵詞,適用於match against操作
BTree索引:B-Tree索引的限制:如果不是按照索引的出現順序查找,則無法使用索引;不能跳過索引中的列,否則後面的索引無效;如果查詢中有某個列的範圍查詢,則其右邊所有列都無法使用索引優化查找;
B+Tree索引:適用於全鍵匹配、第一列匹配(組合索引)、列前綴匹配,範圍值匹配、精確匹配第一列並範圍匹配第二列、只訪問索引(也稱索引覆蓋)匹配;
–title,time
–title
6.索引覆蓋:如果要查找的數據恰好是索引列,那麽就不用在去物理磁盤上去找數據了,就是不用回行,稱為索引覆蓋;
7.索引優化:雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對表進行INSERT、UPDATE和DELETE。因為更新表時,MySQL不僅要保存數據,還要保存一下索引文件。建立索引會占用磁盤空間的索引文件。一般情況這個問題不太嚴重,但如果你在一個大表上創建了多種組合索引,索引文件的會膨脹很快。索引只是提高效率的一個因素,如果你的MySQL有大數據量的表,就需要花時間研究建立最優秀的索引,或優化查詢語句。
a. 何時使用聚集索引或非聚集索引?
事實上,我們可以通過前面聚集索引和非聚集索引的定義的例子來理解上表。如:返回某範圍內的數據一項。比如您的某個表有一個時間列,恰好您把聚合索引建立在了該列,這時您查詢2004年1月1日至2004年10月1日之間的全部數據時,這個速度就將是很快的,因為您的這本字典正文是按日期進行排序的,聚類索引只需要找到要檢索的所有數據中的開頭和結尾數據即可;而不像非聚集索引,必須先查到目錄中查到每一項數據對應的頁碼,然後再根據頁碼查到具體內容。
b. 索引不會包含有NULL值的列
只要列中包含有NULL值都將不會被包含在索引中,復合索引中只要有一列含有NULL值,那麽這一列對於此復合索引就是無效的。所以我們在數據庫設計時不要讓字段的默認值為NULL。
c. 使用短索引
對字符串列進行索引,如果可能應該指定一個前綴長度。例如,如果有一個CHAR(255)的列,如果在前10個或20個字符內,多數值是惟一的,那麽就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節省磁盤空間和I/O操作。mysql不允許索引這些列(BLOB、TEXT、很長的VARCHAR)的完整長度
d. 索引列排序
MySQL查詢只使用一個索引,因此如果where子句中已經使用了索引的話,那麽order by中的列是不會使用索引的。因此數據庫默認排序可以符合要求的情況下不要使用排序操作;盡量不要包含多個列的排序,如果需要最好給這些列創建復合索引。
只有當索引的列順序和order by子句的順序完全一致,並且所有列的排序方向一致時,mysql才能用索引來對結果做排序
e. like語句操作:一般情況下不鼓勵使用like操作,如果非使用不可,如何使用也是一個問題。like “%aaa%” 不會使用索引。而like “aaa%”可以使用索引。
f. 不要在列上進行運算:
例如:select * from users where YEAR(adddate)<2007,將在每個行上進行運算,這將導致索引失效而進行全表掃描,因此我們可以改成:select * from users where adddate<’2007-01-01′
g.多列索引:
如果對多個單獨索引做AND條件查詢時,應該將多個單獨索引合並為一個多列索引。
如果對多個單獨索引做OR條件查詢,會消耗大量CPU、內存在算法的緩存、排序和合並上。應該將多個單獨索引合並為一個多列索引。
使用explain檢查sql 語句,如果發現了索引合並問題,應該修改sql語句
選擇合適的索引列順序,選擇性高的列往前放
h.覆蓋索引:如果一個索引包含所有要查詢的字段值(三星系統中第三星),較少了磁盤IO操作,提高查詢性能
i.索引不能太多:索引越多會導致更新表的速度減慢,因為除了更新數據外,還要更新索引
j:MySQL只對以下操作符才使用索引 <,<=,=,>,>=,between,in,以及某些時候的like(不以通配符%或_開頭的情形)。而理論上每張表裏面最多可創建16個索引,不過除非是數據量真的很多,否則過多的使用索引也不是那麽好玩的
8.非聚簇索引和.聚簇索引
非聚集索引,類似於圖書的附錄,那個專業術語出現在哪個章節,這些專業術語是有順序的,但是出現的位置是沒有順序的。每個表只能有一個聚簇索引,因為一個表中的記錄只能以一種物理順序存放。但是,一個表可以有不止一個非聚簇索引。
MyISAM是非聚簇索引,B+Tree的葉子節點上的data,並不是數據本身,而是數據存放的地址。主索引和輔助索引沒啥區別,只是主索引中的key一定得是唯一的。這裏的索引都是非聚簇索引。非聚簇索引的兩棵B+樹看上去沒什麽不同,節點的結構完全一致只是存儲的內容不同而已,主鍵索引B+樹的節點存儲了主鍵,輔助鍵索引B+樹存儲了輔助鍵。表數據存儲在獨立的地方,
這兩顆B+樹的葉子節點都使用一個地址指向真正的表數據,對於表數據來說,這兩個鍵沒有任何差別。由於索引樹是獨立的,通過輔助鍵檢索無需訪問主鍵的索引樹。InnoDB的數據文件本身就是索引文件,B+Tree的葉子節點上的data就是數據本身,key為主鍵,這是聚簇索引。聚簇索引,葉子節點上的data是主鍵(所以聚簇索引的key,不能過長)。
聚簇索引的數據的物理存放順序與索引順序是一致的,即:只要索引是相鄰的,那麽對應的數據一定也是相鄰地存放在磁盤上的。聚簇索引要比非聚簇索引查詢效率高很多。
聚集索引這種主+輔索引的好處是,當發生數據行移動或者頁分裂時,輔助索引樹不需要更新,因為輔助索引樹存儲的是主索引的主鍵關鍵字,而不是數據具體的物理地址。
MyISAM和InnoDB上都是采用B+Tree索引,但是實現方式完全不同。具體可參考
MySQL的MyISAM與InnoDB的索引方式
https://www.cnblogs.com/zlcxbb/p/5757245.html 4.索引分為聚簇索引和非聚簇索引兩種 innodb采用聚簇索引:主鍵索引的葉子節點下面直接存放數據,其他次索引的葉子節點指向主鍵id;聚簇索引能提高多行檢索的速度。 myisam采用非聚簇索引 :主鍵索引的葉子節點只存放數據在物理磁盤上的指針,其他次索引也是一樣的;非聚簇索引對於單行的檢索很快 5.按照使用方式來劃分索引類型a.普通索引INDEX :這是最基本的索引,它沒有任何限制。
b.唯一索引UNIQUE:與普通索引類似,不同的就是:索引列的值必須唯一,但允許有空值。如果是組合索引,則列值的組合必須唯一
c.主鍵索引PRIMARY KEY:它 是一種特殊的唯一索引,不允許有空值。
d.全文索引FULLTEXT :僅可用於 MyISAM 表,針對較大的數據,生成全文索引很耗時耗空間。
e. 單列索引、多列索引:多個單列索引與單個多列索引的查詢效果不同,因為執行查詢時,MySQL只能使用一個索引,會從多個索引中選擇一個限制最為嚴格的索引。
f.組合索引:為了榨取MySQL的效率,就要考慮建立組合索引。例如表中針對title和time建立一個組合索引:ALTER TABLE article ADD INDEX index_titme_time (title(50),time(10))。建立這樣的組合索引,其實是相當於分別建立了下面兩組組合索引,為什麽沒有time這樣的組合索引呢?這是因為MySQL組合索引“最左前綴”的結果。簡單的理解就是只從最左面的開始組合。並不是只要包含這兩列的查詢都會用到該組合索引
動作描述 | 使用聚集索引 | 使用非聚集索引 |
列經常被分組排序 | 使用 | 使用 |
返回某範圍內的數據 | 使用 | 不使用 |
一個或極少不同值 | 不使用 | 不使用 |
小數目的不同值 | 使用 | 不使用 |
大數目的不同值 | 不使用 | 使用 |
頻繁更新的列 | 不使用 | 使用 |
外鍵列 | 使用 | 使用 |
主鍵列 | 使用 | 使用 |
頻繁修改索引列 | 不使用 | 使用 |
InnoDB是聚簇索引,將主鍵組織到一棵B+樹中,而行數據就儲存在葉子節點上,若使用"where id = 14"這樣的條件查找主鍵,則按照B+樹的檢索算法即可查找到對應的葉節點,之後獲得行數據。若對Name列進行條件搜索,則需要兩個步驟:第一步在輔助索引B+樹中檢索Name,到達其葉子節點獲取對應的主鍵。第二步使用主鍵在主索引B+樹種再執行一次B+樹檢索操作,最終到達葉子節點即可獲取整行數據。
9.mysql索引和頁的關系
索引往往以索引文件的形式存儲的磁盤上,索引的結構組織要盡量減少查找過程中磁盤I/O的存取次數。為了達到這個目的,磁盤按需讀取,要求每次都會預讀的長度一般為頁的整數倍。而且數據庫系統將一個節點的大小設為等於一個頁,這樣每個節點只需要一次I/O就可以完全載入。每次新建節點時,直接申請一個頁的空間,這樣就保證一個節點物理上也存儲在一個頁裏,加之計算機存儲分配都是按頁對齊的,就實現了一個node只需一次I/O。並把B-tree中的m值設的非常大,就會讓樹的高度降低,有利於一次完全載入。 內存管理內容可參考操作系統內存管理mysql索引介紹