1. 程式人生 > >mysql學習與提高3:mysql索引

mysql學習與提高3:mysql索引

目錄

索引

B Tree 原理

索引分類

B+Tree 索引

雜湊索引

全文索引

空間資料索引(R-Tree)

索引的特點

索引的優點

索引的缺點

索引失效

在什麼情況下適合建立索引

為什麼用B+樹做索引而不用B-樹或紅黑樹

聯合索引

什麼是聯合索引

命名規則

建立索引

索引型別

刪除索引

什麼情況下使用索引


索引

索引是什麼呢?簡而言之,索引就是一種高效找到資料的一種資料結構。

比如我們查字典,如果我們查每個字都從第一頁開始翻,直到找到我們的目標為止的話,顯然效率是十分低下的。所以便有了我們的拼音索引表,根據這個索引表,我們找每個字的時間就大大縮短了。

B Tree 原理

B-Tree

 

定義一條資料記錄為一個二元組 [key, data],B-Tree 是滿足下列條件的資料結構:

  • 所有葉節點具有相同的深度,也就是說 B-Tree 是平衡的;
  • 一個節點中的 key 從左到右非遞減排列;
  • 如果某個指標的左右相鄰 key 分別是 keyi 和 keyi+1,且不為 null,則該指標指向節點的(所有 key ≥ keyi) 且(key ≤ keyi+1)。

查詢演算法:首先在根節點進行二分查詢,如果找到則返回對應節點的 data,否則在相應區間的指標指向的節點遞迴進行查詢。

由於插入刪除新的資料記錄會破壞 B-Tree 的性質,因此在插入刪除時,需要對樹進行一個分裂、合併、旋轉等操作以保持 B-Tree 性質。

B+Tree

 

與 B-Tree 相比,B+Tree 有以下不同點:

  • 每個節點的指標上限為 2d 而不是 2d+1(d 為節點的出度);
  • 內節點不儲存 data,只儲存 key;
  • 葉子節點不儲存指標。

順序訪問指標

 

一般在資料庫系統或檔案系統中使用的 B+Tree 結構都在經典 B+Tree 基礎上進行了優化,在葉子節點增加了順序訪問指標,做這個優化的目的是為了提高區間訪問的效能。

優勢

紅黑樹等平衡樹也可以用來實現索引,但是檔案系統及資料庫系統普遍採用 B Tree 作為索引結構,主要有以下兩個原因:

(一)更少的檢索次數

平衡樹檢索資料的時間複雜度等於樹高 h,而樹高大致為 O(h)=O(logdN),其中 d 為每個節點的出度。

紅黑樹的出度為 2,而 B Tree 的出度一般都非常大。紅黑樹的樹高 h 很明顯比 B Tree 大非常多,因此檢索的次數也就更多。

B+Tree 相比於 B-Tree 更適合外存索引,因為 B+Tree 內節點去掉了 data 域,因此可以擁有更大的出度,檢索效率會更高。

(二)利用計算機預讀特性

為了減少磁碟 I/O,磁碟往往不是嚴格按需讀取,而是每次都會預讀。這樣做的理論依據是電腦科學中著名的區域性性原理:當一個數據被用到時,其附近的資料也通常會馬上被使用。預讀過程中,磁碟進行順序讀取,順序讀取不需要進行磁碟尋道,並且只需要很短的旋轉時間,因此速度會非常快。

作業系統一般將記憶體和磁碟分割成固態大小的塊,每一塊稱為一頁,記憶體與磁碟以頁為單位交換資料。資料庫系統將索引的一個節點的大小設定為頁的大小,使得一次 I/O 就能完全載入一個節點,並且可以利用預讀特性,相鄰的節點也能夠被預先載入。

更多內容請參考:MySQL 索引背後的資料結構及演算法原理

索引分類

特性 說明 InnoDB MyISAM MEMORY
B樹索引 (B-tree indexes) 自增ID物理連續性更高,
二叉樹,紅黑樹高度不可控
R樹索引 (R-tree indexes) 空間索引    
雜湊索引 (Hash indexes) 無法做範圍查詢  
全文索引 (Full-text indexes)    

B+Tree 索引

B+Tree 索引是大多數 MySQL 儲存引擎的預設索引型別。

因為不再需要進行全表掃描,只需要對樹進行搜尋即可,因此查詢速度快很多。除了用於查詢,還可以用於排序和分組。

可以指定多個列作為索引列,多個索引列共同組成鍵。

B+Tree 索引適用於全鍵值、鍵值範圍和鍵字首查詢,其中鍵字首查詢只適用於最左字首查詢。

如果不是按照索引列的順序進行查詢,則無法使用索引。

InnoDB 的 B+Tree 索引分為主索引輔助索引

主索引的葉子節點 data 域記錄著完整的資料記錄,這種索引方式被稱為聚簇索引。因為無法把資料行存放在兩個不同的地方,所以一個表只能有一個聚簇索引。

 

輔助索引的葉子節點的 data 域記錄著主鍵的值,因此在使用輔助索引進行查詢時,需要先查詢到主鍵值,然後再到主索引中進行查詢。

 

雜湊索引

InnoDB 引擎有一個特殊的功能叫 “自適應雜湊索引”,當某個索引值被使用的非常頻繁時,會在 B+Tree 索引之上再建立一個雜湊索引,這樣就讓 B+Tree 索引具有雜湊索引的一些優點,比如快速的雜湊查詢。

雜湊索引能以 O(1) 時間進行查詢,但是失去了有序性,它具有以下限制:

  • 無法用於排序與分組;
  • 只支援精確查詢,無法用於部分查詢和範圍查詢;

全文索引

MyISAM 儲存引擎支援全文索引,用於查詢文字中的關鍵詞,而不是直接比較是否相等。查詢條件使用 MATCH AGAINST,而不是普通的 WHERE。

全文索引一般使用倒排索引實現,它記錄著關鍵詞到其所在文件的對映。

InnoDB 儲存引擎在 MySQL 5.6.4 版本中也開始支援全文索引。

空間資料索引(R-Tree)

MyISAM 儲存引擎支援空間資料索引,可以用於地理資料儲存。空間資料索引會從所有維度來索引資料,可以有效地使用任意維度來進行組合查詢。

必須使用 GIS 相關的函式來維護資料。

索引的特點

  • 可以加快資料庫的檢索速度
  • 降低資料庫插入、修改、刪除等維護的速度
  • 只能建立在表上,不能建立到檢視上
  • 既可以直接建立又可以間接建立
  • 可以在優化隱藏中使用索引
  • 使用查詢處理器執行SQL語句,在一個表上,一次只能使用一個索引

索引的優點

  • 建立唯一性索引,保證資料庫表中每一行資料的唯一性
  • 大大加快資料的檢索速度,這是建立索引的最主要的原因
  • 加速資料庫表之間的連線,特別是在實現資料的參考完整性方面特別有意義
  • 在使用分組和排序子句進行資料檢索時,同樣可以顯著減少查詢中分組和排序的時間
  • 通過使用索引,可以在查詢中使用優化隱藏器,提高系統的效能

索引的缺點

  • 建立索引和維護索引要耗費時間,這種時間隨著資料量的增加而增加
  • 索引需要佔用物理空間,除了資料表佔用資料空間之外,每一個索引還要佔一定的物理空間,如果建立聚簇索引,那麼需要的空間就會更大
  • 當對錶中的資料進行增加、刪除和修改的時候,索引也需要維護,降低資料維護的速度

索引失效

  • 如果MySQL估計使用全表掃秒比使用索引快,則不適用索引。

    例如,如果列key均勻分佈在1和100之間,下面的查詢使用索引就不是很好:select * from table_name where key>1 and key<90;

  • 如果條件中有or,即使其中有條件帶索引也不會使用

    例如:select * from table_name where key1='a' or key2='b';如果在key1上有索引而在key2上沒有索引,則該查詢也不會走索引

  • 複合索引,如果索引列不是複合索引的第一部分,則不使用索引(即不符合最左字首)

    例如,複合索引為(key1,key2),則查詢select * from table_name where key2='b';將不會使用索引

  • 如果like是以 % 開始的,則該列上的索引不會被使用。

    例如select * from table_name where key1 like '%a';該查詢即使key1上存在索引,也不會被使用如果列型別是字串,那一定要在條件中使用引號引起來,否則不會使用索引

  • 如果列為字串,則where條件中必須將字元常量值加引號,否則即使該列上存在索引,也不會被使用。

    例如,select * from table_name where key1=1;如果key1列儲存的是字串,即使key1上有索引,也不會被使用。

  • 如果使用MEMORY/HEAP表,並且where條件中不使用“=”進行索引列,那麼不會用到索引,head表只有在“=”的條件下才會使用索引

在什麼情況下適合建立索引

  • 為經常出現在關鍵字order by、group by、distinct後面的欄位,建立索引。
  • 在union等集合操作的結果集欄位上,建立索引。其建立索引的目的同上。
  • 為經常用作查詢選擇 where 後的欄位,建立索引。
  • 在經常用作表連線 join 的屬性上,建立索引。
  • 考慮使用索引覆蓋。對資料很少被更新的表,如果使用者經常只查詢其中的幾個欄位,可以考慮在這幾個欄位上建立索引,從而將表的掃描改變為索引的掃描。

更多資料:MySQL索引背後的資料結構及演算法原理

為什麼用B+樹做索引而不用B-樹或紅黑樹

B+ 樹只有葉節點存放資料,其餘節點用來索引,而 B- 樹是每個索引節點都會有 Data 域。所以從 InooDB 的角度來看,B+ 樹是用來充當索引的,一般來說索引非常大,尤其是關係性資料庫這種資料量大的索引能達到億級別,所以為了減少記憶體的佔用,索引也會被儲存在磁碟上。

  • 那麼 MySQL如何衡量查詢效率呢?答:磁碟 IO 次數

    • B- 樹 / B+ 樹 的特點就是每層節點數目非常多,層數很少,目的就是為了就少磁碟 IO 次數,但是 B- 樹的每個節點都有 data 域(指標),這無疑增大了節點大小,說白了增加了磁碟 IO 次數(磁碟 IO 一次讀出的資料量大小是固定的,單個數據變大,每次讀出的就少,IO 次數增多,一次 IO 多耗時),而 B+ 樹除了葉子節點其它節點並不儲存資料,節點小,磁碟 IO 次數就少。
    • B+ 樹所有的 Data 域在葉子節點,一般來說都會進行一個優化,就是將所有的葉子節點用指標串起來。這樣遍歷葉子節點就能獲得全部資料,這樣就能進行區間訪問啦。在資料庫中基於範圍的查詢是非常頻繁的,而 B 樹不支援這樣的遍歷操作。
  • B 樹相對於紅黑樹的區別

    • AVL 樹和紅黑樹基本都是儲存在記憶體中才會使用的資料結構。在大規模資料儲存的時候,紅黑樹往往出現由於樹的深度過大而造成磁碟 IO 讀寫過於頻繁,進而導致效率低下的情況。為什麼會出現這樣的情況,我們知道要獲取磁碟上資料,必須先通過磁碟移動臂移動到資料所在的柱面,然後找到指定盤面,接著旋轉盤面找到資料所在的磁軌,最後對資料進行讀寫。磁碟IO代價主要花費在查詢所需的柱面上,樹的深度過大會造成磁碟IO頻繁讀寫。根據磁碟查詢存取的次數往往由樹的高度所決定,所以,只要我們通過某種較好的樹結構減少樹的結構儘量減少樹的高度,B樹可以有多個子女,從幾十到上千,可以降低樹的高度。
    • 資料庫系統的設計者巧妙利用了磁碟預讀原理,將一個節點的大小設為等於一個頁,這樣每個節點只需要一次 I/O 就可以完全載入。為了達到這個目的,在實際實現 B-Tree 還需要使用如下技巧:每次新建節點時,直接申請一個頁的空間,這樣就保證一個節點物理上也儲存在一個頁裡,加之計算機儲存分配都是按頁對齊的,就實現了一個 node 只需一次 I/O。

聯合索引

什麼是聯合索引

兩個或更多個列上的索引被稱作聯合索引,聯合索引又叫複合索引。對於複合索引:Mysql 從左到右的使用索引中的欄位,一個查詢可以只使用索引中的一部份,但只能是最左側部分。

例如索引是key index (a,b,c),可以支援[a]、[a,b]、[a,b,c] 3種組合進行查詢,但不支 [b,c] 進行查詢。當最左側欄位是常量引用時,索引就十分有效。

命名規則

  1. 需要加索引的欄位,要在 where 條件中
  2. 資料量少的欄位不需要加索引
  3. 如果 where 條件中是OR關係,加索引不起作用
  4. 符合最左原則

建立索引

在執行 CREATE TABLE 語句時可以建立索引,也可以單獨用 CREATE INDEX 或 ALTER TABLE 來為表增加索引。

ALTER TABLE

ALTER TABLE 用來建立普通索引、UNIQUE 索引或 PRIMARY KEY 索引。

例如:

 ALTER TABLE table_name ADD INDEX index_name (column_list)
 ALTER TABLE table_name ADD UNIQUE (column_list)
 ALTER TABLE table_name ADD PRIMARY KEY (column_list)

其中 table_name 是要增加索引的表名,column_list 指出對哪些列進行索引,多列時各列之間用逗號分隔。索引名 index_name 可選,預設時,MySQL將根據第一個索引列賦一個名稱。另外,ALTER TABLE 允許在單個語句中更改多個表,因此可以在同時建立多個索引。

CREATE INDEX

CREATE INDEX 可對錶增加普通索引或 UNIQUE 索引。

例如:

 CREATE INDEX index_name ON table_name (column_list)
 CREATE UNIQUE INDEX index_name ON table_name (column_list)

table_name、index_name 和 column_list 具有與 ALTER TABLE 語句中相同的含義,索引名不可選。另外,不能用 CREATE INDEX 語句建立 PRIMARY KEY 索引。

索引型別

在建立索引時,可以規定索引能否包含重複值。如果不包含,則索引應該建立為 PRIMARY KEY 或 UNIQUE 索引。對於單列惟一性索引,這保證單列不包含重複的值。對於多列惟一性索引,保證多個值的組合不重複。 PRIMARY KEY 索引和 UNIQUE 索引非常類似。

事實上,PRIMARY KEY 索引僅是一個具有名稱 PRIMARY 的 UNIQUE 索引。這表示一個表只能包含一個 PRIMARY KEY,因為一個表中不可能具有兩個同名的索引。 下面的SQL語句對 students 表在 sid 上新增 PRIMARY KEY 索引。 ​ ALTER TABLE students ADD PRIMARY KEY (sid)

刪除索引

可利用 ALTER TABLE 或 DROP INDEX 語句來刪除索引。類似於 CREATE INDEX 語句,DROP INDEX 可以在 ALTER TABLE 內部作為一條語句處理,語法如下。

 DROP INDEX index_name ON talbe_name
 ALTER TABLE table_name DROP INDEX index_name
 ALTER TABLE table_name DROP PRIMARY KEY

其中,前兩條語句是等價的,刪除掉 table_name 中的索引 index_name。

第3條語句只在刪除 PRIMARY KEY 索引時使用,因為一個表只可能有一個 PRIMARY KEY 索引,因此不需要指定索引名。如果沒有建立 PRIMARY KEY 索引,但表具有一個或多個 UNIQUE 索引,則 MySQL 將刪除第一個 UNIQUE 索引。

如果從表中刪除了某列,則索引會受到影響。對於多列組合的索引,如果刪除其中的某列,則該列也會從索引中刪除。如果刪除組成索引的所有列,則整個索引將被刪除。

什麼情況下使用索引

  1. 為了快速查詢匹配WHERE條件的行。
  2. 為了從考慮的條件中消除行。
  3. 如果表有一個multiple-column索引,任何一個索引的最左字首可以通過使用優化器來查詢行。
  4. 查詢中與其它表關聯的字,欄位常常建立了外來鍵關係
  5. 查詢中統計或分組統計的欄位
    • select max(hbs_bh) from zl_yhjbqk
    • select qc_bh,count(*) from zl_yhjbqk group by qc_bh