MySQL的索引

概述:mysql

  索引(Index)是幫助MySQL高效獲取數據的數據結構。算法

  索引是以表列爲基礎的數據庫對象,它保存着表中排序的索引列,而且記錄了索引列在數據表中的物理存儲位置,實現了表中數據的邏輯排序,sql

  其主要目的是提升數據庫系統的性能,加快數據的查詢速度和減小系統的響應時間。數據庫

  在MySQL中,索引是在存儲引擎層而不是服務器層實現的。因此每種存儲引擎的索引都不必定徹底相同。服務器

 

 

MYSQL目前提供了一下4種索引:數據結構

  B-Tree 索引:最多見的索引類型,大部分引擎都支持B樹索引。Innodb 存儲引擎的 B-Tree 索引實際使用的存儲結構其實是 B+樹。
  HASH 索引:只有Memory引擎支持,使用場景簡單。
  R-Tree 索引(空間索引):空間索引是MyISAM的一種特殊索引類型,主要用於地理空間數據類型。
  Full-text (全文索引):全文索引也是MyISAM的一種特殊索引類型,主要用於全文檢索,InnoDB從MYSQL5.6版本提供對全文索引的支持。oracle

 

B-Tree索引:函數

  也就是一般所指的索引。性能

  InnoDB使用B+Tree這種數據結構。優化

  B+Tree:每個葉子節點都包含指向下一個葉子節點的指針,從而方便葉子節點的範圍遍歷。

  適合查找範圍數據。好比:找出全部以I到K開頭的名字。

 

B-Tree索引具體又可分爲:

普通索引:

  最基本的索引類型。

–直接建立索引
CREATE INDEX index_name ON table(column(length))

–修改表結構的方式添加索引
ALTER TABLE table_name ADD INDEX index_name ON (column(length))   

–建立表的時候同時建立索引
CREATE TABLE `table` (
`id` int(11) NOT NULL AUTO_INCREMENT ,
`title` char(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
`content` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL ,
`time` int(10) NULL DEFAULT NULL ,
PRIMARY KEY (`id`),
INDEX index_name (title(length))
)

–刪除索引
DROP INDEX index_name ON table

 

 

惟一索引:

  索引列的值必須惟一,但容許有空值(注意和主鍵不一樣)。若是是組合索引,則列值的組合必須惟一。

–建立惟一索引
CREATE UNIQUE INDEX indexName ON table(column(length))

–修改表結構
ALTER TABLE table_name ADD UNIQUE indexName ON (column(length))

–建立表的時候直接指定
CREATE TABLE `table` (
`id` int(11) NOT NULL AUTO_INCREMENT ,
`title` char(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
`content` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL ,
`time` int(10) NULL DEFAULT NULL ,
PRIMARY KEY (`id`),
UNIQUE indexName (title(length))
);

 

主鍵索引:

  它是一種特殊的惟一索引,不容許有空值。通常是在建表的時候同時建立主鍵索引。

  也能夠用 ALTER 命令,但不能用CREATE INDEX語句建立主鍵索引。

  每一個表只能有一個主鍵。 (主鍵至關於聚合索引,是查找最快的索引)

CREATE TABLE mytable(  
ID INT NOT NULL,   
username VARCHAR(16) NOT NULL,  
PRIMARY KEY(ID)  
); 

 

 

 

多列索引(組合索引):

  ALTER  TABLE  table_name  ADD  INDEX  indexName( name, address ) ; 

  對於多列組合的索引,若是刪除其中的某列,則該列也會從索引中刪除。若是刪除組成索引的全部列,則整個索引將被刪除。

 

根據數據的存儲方式的不一樣,B-Tree索引又可分爲彙集索引和非彙集索引

彙集索引:

  CREATE CLUSTERED INDEX indexName ON mytable(mycolumn)

  InnoDB的彙集索引其實是在同一個結構中保存了B-Tree索引和數據行。

  由於沒法同時把數據行存放在兩個不一樣的地方,因此一個表只能有一個彙集索引。

  表數據按照索引的順序來存儲的,也就是說索引項的順序與表中記錄的物理順序一致。

  對於彙集索引, 葉子結點即存儲了真實的數據行,再也不有另外單獨的數據頁 

 

非彙集索引 : 

  CREATE UNCLUSTERED INDEX indexName ON mytable(mycolumn)

  表數據存儲順序與索引順序無關。

  對於非彙集索引,葉結點包含索引字段值及指向數據頁數據行的邏輯指針,其行數量與數據錶行數據量一致。

 

可使用B-Tree索引的查詢類型,以多列索引key(last_name, first_name, dob)爲例:

  • 全值匹配:指定查詢的人的fitst_name, last_name和dob;
  • 匹配最左前綴:查找指定了last_name的記錄;
  • 匹配列前綴:匹配某一列的值的開頭部分,好比last_name以J開頭;
  • 精確匹配某一列並範圍匹配另外一列:查找last_name爲Allen,而且first_name以k開頭的;
  • 只訪問索引的查詢:B-Tree一般能夠支持只訪問索引的查詢,即查詢只須要訪問索引,而無需訪問數據行。

 

B-Tree的一些限制:

  1. 若是不是按照從最左列開始查找,則沒法使用索引。例如沒法查找只指定了first_name或者dob的記錄;
  2. 不能跳過索引中的列:不能在查找的時候只指定了last_name和dob,那麼dob不會使用索引。
  3. 若是查詢的時候有某個列的查詢範圍,則其右邊的全部列都沒法使用索引優化查找。好比對last_name使用了like,那麼first_name和dob將不會使用索引。

 

哈希索引:

  基於哈希表實現,只有精確匹配索引全部列的查詢纔有效。

  由於它對每行中的全部索引列計算出一個哈希碼,做爲哈希表的鍵(原理是基於拉鍊法的解決碰撞的策略)。

  在MySQL中只有Memory引擎顯式地支持哈希索引,Memory引擎同時也支持B-Tree索引。

  InnoDB中的自適應哈希索引:某些索引值使用很是頻繁時,會在內存中基於B-Tree索引只上再建立一個hash索引。

 

哈希索引的一些限制:

  1. 哈希索引只包含哈希值和行指針,而不存儲字段值,因此不能用索引中的值來避免讀取行
  2. 哈希索引數據並非按照索引值順序存儲的,因此也就沒法用於排序
  3. 哈希索引不支持部分列匹配查找,由於它用全部索引列來計算獲得哈希值。
  4. 索引列只支持等值查詢,理由同上;
  5. 哈希索引數據查找很是快,除非有不少哈希衝突;
  6. 若是哈希衝突比較高,一些索引維護操做的代價也會很高。好比性別字段,衝突會很高。

 

空間數據索引(R-Tree):

  ALTER  TABLE  table_name  ADD  SPATIAL  INDEX  indexName( line ) ; 

  MyISAM表支持空間索引,能夠用做地理數據存儲。

  空間索引會從全部維度來索引數據,能夠有效地使用任意維度來進行組合查詢。

  必須使用 GIS 相關的函數來維護數據。

 

全文索引:

  它查找的是文本中的關鍵詞,而不是直接比較索引中的值。

  使用 MATCH AGAINST,而不是普通的 WHERE。

–直接建立索引
CREATE FULLTEXT INDEX index_content ON article(content)

 –修改表結構添加全文索引
 ALTER TABLE article ADD FULLTEXT index_content(content)

 

 

 索引的優勢:

  建立惟一性索引,保證數據庫表中每一行數據的惟一性
  大大加快數據的檢索速度,這也是建立索引的最主要的緣由
  加速表和表之間的鏈接,特別是在實現數據的參考完整性方面特別有意義。
  在使用分組和排序子句進行數據檢索時,一樣能夠顯著減小查詢中分組和排序的時間。
  經過使用索引,能夠在查詢的過程當中使用優化隱藏器,提升系統的性能。

 


索引的缺點 :
  建立索引和維護索引要耗費時間,這種時間隨着數據量的增長而增長
  索引須要佔物理空間,除了數據表佔數據空間以外,每個索引還要佔必定的物理空間,若是要創建聚簇索引,那麼須要的空間就會更大
  當對錶中的數據進行增長、刪除和修改的時候,索引也要動態的維護,下降了數據的維護速度

 

應該在這些列上建立索引:

  在常常須要搜索的列上,能夠加快搜索的速度; 
  在做爲主鍵的列上,強制該列的惟一性和組織表中數據的排列結構; 
  在常常用在鏈接的列上,這些列主要是一些外鍵,能夠加快鏈接的速度; 
  在常常須要根據範圍進行搜索的列上建立索引,由於索引已經排序,其指定的範圍是連續的; 
  在常常須要排序的列上建立索引,由於索引已經排序,這樣查詢能夠利用索引的排序,加快排序查詢時間; 
  在常用在WHERE子句中的列上面建立索引,加快條件的判斷速度。

 

不該該建立索引的的這些列具備下列特色:

  第一,對於那些在查詢中不多使用或者參考的列不該該建立索引。這是由於,既然這些列不多使用到,所以有索引或者無索引,並不能提升查詢速度。相反,因爲增長了索引,反而下降了系統的維護速度和增大了空間需求。 
  第二,對於那些只有不多數據值的列也不該該增長索引。這是由於,因爲這些列的取值不多,例如人事表的性別列,在查詢的結果中,結果集的數據行佔了表中數據行的很大比例,即須要在表中搜索的數據行的比例很大。增長索引,並不能明顯加快檢索速度。 
  第三,對於那些定義爲text, image和bit數據類型的列不該該增長索引。這是由於,這些列的數據量要麼至關大,要麼取值不多。 
  第四,當修改性能遠遠大於檢索性能時,不該該建立索引。這是由於,修改性能和檢索性能是互相矛盾的。當增長索引時,會提升檢索性能,可是會下降修改性能。當減小索引時,會提升修改性能,下降檢索性能。所以,當修改性能遠遠大於檢索性能時,不該該建立索引。

 

索引選擇原則:

  較頻繁的做爲查詢條件的字段應該建立索引

  定義有主鍵的數據列必定要創建索引。由於主鍵能夠加速定位到表中的某一行。 

  定義有外鍵的數據列必定要創建索引。外鍵列一般用於表與表之間的鏈接,在其上建立索引能夠加快表間的鏈接。

  惟一性太差的字段不適合單首創建索引,即便頻繁做爲查詢條件,好比性別只有男,女

  更新很是頻繁的字段不適合建立索引

  不會出如今 WHERE 子句中的字段不應建立索引

  表記錄比較少,例如一兩千條甚至只有幾百條記錄的表,不必建索引,讓查詢作全表掃描就行了;

  對於定義爲text、image和bit數據類型的列不要創建索引。

  能夠考慮使用索引的主要有 兩種類型的列:在where子句中出現的列,在join子句中出現的列,而不是在SELECT關鍵字後選擇列表的列;

  使用短索引,若是對字符串列進行索引,應該指定一個前綴長度,可節省大量索引空間,提高查詢速度;好比很長的字符串,對前10個或者20個字符進行索引可以節省大量索引空間,也可能會使查詢更快。

  利用最左前綴:Mysql會一直向右查找直到遇到範圍操做(>,<,like、between)就中止匹配。好比a=1 and b=2 and c>3 and d=6;此時若是創建了(a,b,c,d)索引,那麼後面的d索引是徹底沒有用到,當換成了(a,b,d,c)就能夠用到。

  MySQL只對一下操做符才使用索引:<,<=,=,>,>=,between,in, 以及某些時候的like(不以通配符%或_開頭的情形)。

  不要過分索引,只保持所需的索引。每一個額外的索引都要佔用額外的磁盤空間,並下降寫操做的性能。 在修改表的內容時,索引必須進行更新,有時可能須要重構,所以,索引越多,所花的時間越長。

 

惟一索引與主鍵索引的比較:

惟一索引:
  惟一索引不容許兩行具備相同的索引值。
主鍵索引:
  主鍵索引是惟一索引的特殊類型。
  數據庫表一般有一列或列組合,其值用來惟一標識表中的每一行。該列稱爲表的主鍵。
  在數據庫關係圖中爲表定義一個主鍵將自動建立主鍵索引,主鍵索引是惟一索引的特殊類型。主鍵索引要求主鍵中的每一個值是惟一的。當在查詢中使用主鍵索引時,它還容許快速訪問數據。
 
它們的一些比較:
  (1)對於主健/unique constraint , oracle/sql server/mysql等都會自動創建惟一索引;
  (2)主鍵不必定只包含一個字段,因此若是你在主鍵的其中一個字段建惟一索引仍是必要的;
  (3)主健可做外健,惟一索引不可;
  (4)主健不可爲空,惟一索引可;(惟一索引還能夠有多個NULL值)
  (5)主健也但是多個字段的組合;
  (6)主鍵與惟一索引不一樣的是:
    a.有not null屬性;
    b.每一個表只能有一個。
 
索引失效:
  1. 若是條件中有or,即便其中有條件帶索引也不會使用(這也是爲何儘可能少用or的緣由。要想使用or,又想讓索引生效,只能將or條件中的每一個列都加上索引)
  2. 對於多列索引,不是使用的第一部分,則不會使用索引
  3. like查詢是以%開頭
  4. 若是列類型是字符串,那必定要在條件中將數據使用引號引用起來,不然不使用索引

 

Hash索引和btree索引的區別:

Hash 索引結構的特殊性,其檢索效率很是高,索引的檢索能夠一次定位,不像B-Tree 索引須要從根節點到枝節點,最後才能訪問到頁節點這樣屢次的IO訪問,因此 Hash 索引的查詢效率要遠高於 B-Tree 索引。
(1)Hash 索引僅僅能知足"=","IN"和"<=>"查詢,不能使用範圍查詢。
  因爲 Hash 索引比較的是進行 Hash 運算以後的 Hash 值,因此它只能用於等值的過濾,不能用於基於範圍的過濾,由於通過相應的 Hash 算法處理以後的 Hash 值的大小關係,並不能保證和Hash運算前徹底同樣。
(2)Hash 索引沒法被用來避免數據的排序操做。
  因爲 Hash 索引中存放的是通過 Hash 計算以後的 Hash 值,並且Hash值的大小關係並不必定和 Hash 運算前的鍵值徹底同樣,因此數據庫沒法利用索引的數據來避免任何排序運算;
(3)Hash 索引不能利用部分索引鍵查詢。
    對於組合索引,Hash 索引在計算 Hash 值的時候是組合索引鍵合併後再一塊兒計算 Hash 值,而不是單獨計算 Hash 值,因此經過組合索引的前面一個或幾個索引鍵進行查詢的時候,Hash 索引也沒法被利用。
(4)Hash 索引在任什麼時候候都不能避免表掃描。
    前面已經知道,Hash 索引是將索引鍵經過 Hash 運算以後,將 Hash運算結果的 Hash 值和所對應的行指針信息存放於一個 Hash 表中,因爲不一樣索引鍵存在相同 Hash 值,因此即便取知足某個 Hash 鍵值的數據的記錄條數,也沒法從 Hash 索引中直接完成查詢,仍是要經過訪問表中的實際數據進行相應的比較,並獲得相應的結果。
(5)Hash 索引遇到大量Hash值相等的狀況後性能並不必定就會比B-Tree索引高。
  對於選擇性比較低的索引鍵,若是建立 Hash 索引,那麼將會存在大量記錄指針信息存於同一個 Hash 值相關聯。這樣要定位某一條記錄時就會很是麻煩,會浪費屢次表數據的訪問,而形成總體性能低下。
 
 
  若是存儲的數據重複度很低(也就是說基數很大),對該列數據以等值查詢爲主,沒有範圍查詢、沒有排序的時候,特別適合採用哈希索引
相關文章
相關標籤/搜索