以下索引知識以mysql索引來闡述
一:MySQL中索引的語法
(1)創建索引
--在創建表的時候添加索引 CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, INDEX [indexName] (username(length)) ); --在創建表以后添加索引 ALTER TABLE my_table ADD [UNIQUE] INDEX index_name(column_name); --或者 CREATE INDEX index_name ON my_table(column_name);
注意:
1、索引需要占用磁盤空間,因此在創建索引時要考慮到磁盤空間是否足夠
2、創建索引時需要對表加鎖,因此實際操作中需要在業務空閑期間進行
(2)索引相關sql
--刪除索引 DROP INDEX my_index ON tablename; --或者 ALTER TABLE table_name DROP INDEX index_name; --查看表中的索引 SHOW INDEX FROM tablename --查看查詢語句使用索引的情況 //explain 加查詢語句 explain SELECT * FROM table_name WHERE column_1='123';
二:索引的優缺點
優勢:可以快速檢索,減少I/O次數,加快檢索速度;根據索引分組和排序,可以加快分組和排序;
劣勢:索引本身也是表,因此會占用存儲空間,一般來說,索引表占用的空間的數據表的1.5倍;索引表的維護和創建需要時間成本,這個成本隨着數據量增大而增大;構建索引會降低數據表的修改操作(刪除,添加,修改)的效率,因為在修改數據表的同時還需要修改索引表;
三:索引的分類
常見的索引類型有:主鍵索引、唯一索引、普通索引、全文索引、組合索引
--1、主鍵索引:即主索引,根據主鍵pk_clolum(length)建立索引,不允許重復,不允許空值; ALTER TABLE 'table_name' ADD PRIMARY KEY pk_index('col'); --2、唯一索引:用來建立索引的列的值必須是唯一的,允許空值 ALTER TABLE 'table_name' ADD UNIQUE index_name('col'); --3、普通索引:用表中的普通列構建的索引,沒有任何限制 ALTER TABLE 'table_name' ADD INDEX index_name('col'); --4、全文索引:用大文本對象的列構建的索引 ALTER TABLE 'table_name' ADD FULLTEXT INDEX ft_index('col'); --5、組合索引:用多個列組合構建的索引,這多個列中的值不允許有空值 ALTER TABLE 'table_name' ADD INDEX index_name('col1','col2','col3');
** 組合索引 (最左前綴原則)**
*遵循“最左前綴”原則,把最常用作為檢索或排序的列放在最左,依次遞減,組合索引相當於建立了col1,col1col2,col1col2col3三個索引,而col2或者col3是不能使用索引的。
*在使用組合索引的時候可能因為列名長度過長而導致索引的key太大,導致效率降低,在允許的情況下,可以只取col1和col2的前幾個字符作為索引
ALTER TABLE 'table_name' ADD INDEX index_name(col1(4),col2(3));
例子:
(1)索引(a,b) 查詢條件b是無法使用聯合索引的 查詢條件a可以使用索引
(2)%%開頭是不會使用索引的
**幾種樹的數據結構圖

三:索引的底層數據結構 (B+Tree索引 )
B+Tree索引 : B+Tree是BTree的一個變種,設d為樹的度數,h為樹的高度,B+Tree和BTree的不同主要在於;
- B+Tree中的非葉子結點不存儲數據,只存儲鍵值;
- B+Tree的葉子結點沒有指針,所有鍵值都會出現在葉子結點上,且key存儲的鍵值對應data數據的物理地址;
- B+Tree的每個非葉子節點由n個鍵值key和n個指針point組成;
B+Tree的結構如下:

B+Tree對比BTree的優點:
1、磁盤讀寫代價更低
一般來說B+Tree比BTree更適合實現外存的索引結構,因為存儲引擎的設計專家巧妙的利用了外存(磁盤)的存儲結構,即磁盤的最小存儲單位是扇區(sector),而操作系統的塊(block)通常是整數倍的sector,操作系統以頁(page)為單位管理內存,一頁(page)通常默認為4K,數據庫的頁通常設置為操作系統頁的整數倍,因此索引結構的節點被設計為一個頁的大小,然后利用外存的“預讀取”原則,每次讀取的時候,把整個節點的數據讀取到內存中,然后在內存中查找,已知內存的讀取速度是外存讀取I/O速度的幾百倍,那么提升查找速度的關鍵就在於盡可能少的磁盤I/O,那么可以知道,每個節點中的key個數越多,那么樹的高度越小,需要I/O的次數越少,因此一般來說B+Tree比BTree更快,因為B+Tree的非葉節點中不存儲data,就可以存儲更多的key。
2、查詢速度更穩定
由於B+Tree非葉子節點不存儲數據(data),因此所有的數據都要查詢至葉子節點,而葉子節點的高度都是相同的,因此所有數據的查詢速度都是一樣的。
帶順序索引的B+TREE
很多存儲引擎在B+Tree的基礎上進行了優化,添加了指向相鄰葉節點的指針,形成了帶有順序訪問指針的B+Tree,這樣做是為了提高區間查找的效率,只要找到第一個值那么就可以順序的查找后面的值。
順序B+Tree的結構如下:

三:聚簇索引和非聚簇索引
MySQL中最常見的兩種存儲引擎分別是MyISAM和InnoDB,分別實現了非聚簇索引和聚簇索引。
聚簇索引的解釋是:聚簇索引的順序就是數據的物理存儲順序
非聚簇索引的解釋是:索引順序與數據物理排列順序無關
為了更形象說明這兩種索引的區別,我們假想一個表如下圖存儲了4行數據。其中Id作為主索引,Name作為輔助索引。圖示清晰的顯示了聚簇索引和非聚簇索引的差異。

InnoDB使用的是聚簇索引,將主鍵組織到一棵B+樹中,而行數據就儲存在葉子節點上,若使用"where id = 14"這樣的條件查找主鍵,則按照B+樹的檢索算法即可查找到對應的葉節點,之后獲得行數據。若對Name列進行條件搜索,則需要兩個步驟:第一步在輔助索引B+樹中檢索Name,到達其葉子節點獲取對應的主鍵。第二步使用主鍵在主索引B+樹種再執行一次B+樹檢索操作,最終到達葉子節點即可獲取整行數據。
MyISM使用的是非聚簇索引,非聚簇索引的兩棵B+樹看上去沒什么不同,節點的結構完全一致只是存儲的內容不同而已,主鍵索引B+樹的節點存儲了主鍵,輔助鍵索引B+樹存儲了輔助鍵。表數據存儲在獨立的地方,這兩顆B+樹的葉子節點都使用一個地址指向真正的表數據,對於表數據來說,這兩個鍵沒有任何差別。由於索引樹是獨立的,通過輔助鍵檢索無需訪問主鍵的索引樹。
我們重點關注聚簇索引,看上去聚簇索引的效率明顯要低於非聚簇索引,因為每次使用輔助索引檢索都要經過兩次B+樹查找,這不是多此一舉嗎?聚簇索引的優勢在哪?
1 由於行數據和葉子節點存儲在一起,這樣主鍵和行數據是一起被載入內存的,找到葉子節點就可以立刻將行數據返回了,如果按照主鍵Id來組織數據,獲得數據更快。
2 輔助索引使用主鍵作為"指針" 而不是使用地址值作為指針的好處是,減少了當出現行移動或者數據頁分裂時輔助索引的維護工作,使用主鍵值當作指針會讓輔助索引占用更多的空間,換來的好處是InnoDB在移動行時無須更新輔助索引中的這個"指針"。也就是說行的位置(實現中通過16K的Page來定位,后面會涉及)會隨着數據庫里數據的修改而發生變化(前面的B+樹節點分裂以及Page的分裂),使用聚簇索引就可以保證不管這個主鍵B+樹的節點如何變化,輔助索引樹都不受影響。
B+樹所有的關鍵字都出現在葉子節點的鏈表(稠密索引及聚簇索引)中,且鏈表中的關鍵字是有序的。非葉子節點只起索引作用(稀疏索引及非聚簇索引)。
如果語句是 select * from T where ID=500,即主鍵查詢方式,則只需要搜索 ID 這棵 B+樹。
如果語句是 select * from T where k=5,即普通索引查詢方式,則需要先搜索 k 索引樹,ID 的值為 500,再到 ID 索引樹搜索一次。這個過程稱回表。
四:聯合索引

這是一張表格,col1 是主建,col2和col3 是普通字段。那么主索引 對應的 B+樹 結構是這樣子的:

也可以是這樣子的:

現在呢,對col3 建立一個單列索引,原文圖:

看完這個圖也是可以理解的,那么想法來了,如果對 col3 和 col2 建立 聯合索引,那么 B+ 樹會是一個什么樣子的呢?
首先可以肯定的是,肯定只有一棵樹,又因為 最左原則的存在,那么帶着這個想法自己試着畫了下:

建索引語句 CREATE INDEX IDX_XXX ON TABLE(COL3, COL2);
先根據col3 排序,在根據 col2 排序,如上圖。
原文例子中的數據沒有重復數據,為了更好的理解,我自己改了下:

紅色框是改動的地方,把col3 改成有重復數據了,然后 還是對 col3 ,col2建立聯合索引,那么 B+樹 如下:

紅色框是和原來不一樣的地方。
聯合索引在查找的時候,比如要找 Alice,34 這條記錄 WHERE COL3 = 'Alice' AND COL2 = 34
先根據col3 查找 Alice ,找到了2條記錄,在根據col2 查找 34,然后獲取到主鍵 15 ,在根據主鍵去查找 主索引。
如果 是 WHERE COL2 = 34,由於只有聯合索引 (col3, col2),沒有col2 的單列索引。
那么查找的時候,就沒法根據上面的這棵樹來查找 ,只能全表掃描。
所以為什么會有最左原則,就是因為 B+樹 是根據最左邊的字段構建的,我的想法是這樣子的。
五:索引的使用策略
(1)什么時候要使用索引?
1:主鍵自動建立唯一索引;
2:經常作為查詢條件在WHERE或者ORDER BY 語句中出現的列要建立索引;
3:作為排序的列要建立索引;
4:查詢中與其他表關聯的字段,外鍵關系建立索引
5:高並發條件下傾向組合索引;
6:用於聚合函數的列可以建立索引,例如使用了max(column_1)或者count(column_1)時的column_1就需要建立索引
(2)什么時候不要使用索引?
1:經常增刪改的列不要建立索引;
2:有大量重復的列不建立索引;
3:表記錄太少不要建立索引。只有當數據庫里已經有了足夠多的測試數據時,它的性能測試結果才有實際參考價值。如果在測試數據庫里只有幾百條數據記錄,它們往往在執行完第一條查詢命令之后就被全部加載到內存里,這將使后續的查詢命令都執行得非常快--不管有沒有使用索引。只有當數據庫里的記錄超過了1000條、數據總量也超過了MySQL服務器上的內存總量時,數據庫的性能測試結果才有意義。
索引失效的情況:
1:在組合索引中不能有列的值為NULL,如果有,那么這一列對組合索引就是無效的。
2:在一個SELECT語句中,索引只能使用一次,如果在WHERE中使用了,那么在ORDER BY中就不要用了。
3:LIKE操作中,'%aaa%'不會使用索引,也就是索引會失效,但是‘aaa%’可以使用索引。
4:在索引的列上使用表達式或者函數會使索引失效,例如:select * from users where YEAR(adddate)<2007,將在每個行上進行運算,這將導致索引失效而進行全表掃描,因此我們可以改成:select * from users where adddate<’2007-01-01′。其它通配符同樣,也就是說,在查詢條件中使用正則表達式時,只有在搜索模板的第一個字符不是通配符的情況下才能使用索引。
5:在查詢條件中使用不等於,包括<符號、>符號和!=會導致索引失效。特別的是如果對主鍵索引使用!=則不會使索引失效,如果對主鍵索引或者整數類型的索引使用<符號或者>符號不會使索引失效。
6:在查詢條件中使用IS NULL或者IS NOT NULL會導致索引失效。
7:字符串不加單引號會導致索引失效。更准確的說是類型不一致會導致失效,比如字段email是字符串類型的,使用WHERE email=99999 則會導致失敗,應該改為WHERE email='99999'。
8:在查詢條件中使用OR連接多個條件會導致索引失效,除非OR鏈接的每個條件都加上索引,這時應該改為兩次查詢,然后用UNION ALL連接起來。
9:如果排序的字段使用了索引,那么select的字段也要是索引字段,否則索引失效。特別的是如果排序的是主鍵索引則select * 也不會導致索引失效。
10:盡量不要包括多列排序,如果一定要,最好為這隊列構建組合索引;
六:索引的優化
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_colum) ANGAINST(‘word’);
4、使用短索引
對串列進行索引,如果可能應該指定一個前綴長度。例如,如果有一個CHAR(255)的 列,如果在前10 個或20 個字符內,多數值是惟一的,那么就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節省磁盤空間和I/O操作。
