mysql 隐藏中间四位_MySQL知识体系——索引
本文直切主題,針對InnoDB引擎描述索引及優化策略。在開始之前,需要讀者了解:
索引初探
要了解索引,當然要了解其數據結構。樹有很多應用,流行的用法之一是包括UNIX和DOS在內的許多常用操作系統中的目錄結構,二叉查找樹又是Java中兩種集合類TreeSet和TreeMap實現的基礎。那么對于數據庫,I/O是其性能瓶頸所在,減少樹的深度是直接有效的,BTree和B+Tree應運而生。
BTree和B+Tree(Balance-Tree,多路搜索樹,非二叉)
BTree
BTree是一種查找樹,如同二叉查找樹,紅黑樹等,都是為提高查找效率而產生的,BTree也是如此,可以把它看做二叉查找樹的優化升級。二叉查找樹的特點是每個非葉節點都最多只有兩個子節點,但是當數據量非常大時,二叉查找樹的深度過深,搜索算法自根節點向下搜索時,需要訪問的節點也就變的相當多。如果這些節點存儲在外存儲器(磁盤)中,每訪問一個節點,相當于就是進行了一次I/O操作,隨著樹高度的增加,頻繁的I/O操作一定會降低查詢的效率。BTree改二叉為多叉,每個節點存儲更多的指針信息,以此達到減少樹的深度、降低I/O操作數。
使用BTree結構可以顯著減少定位記錄時所經歷的中間過程,從而加快存取速度。
定義(對于一個m階BTree)
- 根節點至少有兩個子節點(除非根結點為葉節點)
- 每個節點有m-1個關鍵字,并且以升序排列
- 位于 m-1和m 關鍵字的子節點的值位于 m-1和m 關鍵字對應的值之間
- 其它節點至少有m/2個子節點
特性
- 關鍵字集合分布在整棵樹中;
- 任何一個關鍵字出現且只出現在一個節點中;
- 搜索有可能在非葉節點結束;
- 其搜索性能等價于在關鍵字全集內做一次二分查找;
- 自動層次控制。
B+Tree
InnoDB 存儲引擎在絕大多數情況下使用B+Tree建立索引,B+Tree也是關系型數據庫中最為常用和有效的索引結構,但是B+Tree索引并不能找到一個給定鍵對應的具體值,它只能找到數據行對應的頁,然后正如上一節所提到的,數據庫把整個頁讀入到內存中,并在內存中查找具體的數據行。
定義(其定義基本與 BTree同,除了:)
- 所有葉節點之間都有一個鏈指針;
- 所有關鍵字都在葉子結點出現;
- 非葉子節點只存儲鍵值信息,數據記錄都存放在葉節點中。
特性
- 單節點可以存儲更多的元素,使得查詢磁盤IO次數更少,更加高效的單元素查找;
- 所有查詢都要查找到葉子節點,查詢性能穩定;
- 葉子節點會包含所有的關鍵字,以及指向數據記錄的指針,并且葉子節點本身是根據關鍵字的大小從小到大順序鏈接,范圍查找性能更優。
區別
B+Tree是BTree的一種變形樹,它與BTree的差異在于:
- B+Tree只有達到葉子結點才命中(BTree可以在非葉子結點命中),其性能也等價于在關鍵字全集做一次二分查找;
- BTree樹每個葉子節點都有雙向指針;
- BTree分支節點和葉節點均保存記錄的關鍵碼和記錄的指針;B+Tree分支節點只保存記錄關鍵碼的復制,無記錄指針。所有記錄都集中在葉節點一層,并且葉節點可以構成一維線性表,便于連續訪問和范圍查詢。
聚集索引和輔助索引
數據庫中的 B+Tree索引可以分為聚集索引(clustered index)和輔助索引(secondary index),它們之間的最大區別就是,聚集索引中存放著一條行記錄的全部信息,而輔助索引中只包含索引列和一個用于查找對應行記錄的“書簽”。即在數據庫的聚集索引中,葉子節點直接包含衛星數據。在輔助索引(NonClustered Index)中,葉節點帶有指向衛星數據的指針。
聚集索引
InnoDB使用了聚集索引存儲數據。
與非聚集索引的區別則是,聚集索引既存儲了索引,也存儲了行值。當一個表有一個聚集索引,它的數據是存儲在索引的葉子頁(leaf pages)上的。因此可以說InnoDB是基于索引的表。
當我們使用聚集索引對表中的數據進行檢索時,可以直接獲得聚集索引所對應的整條行記錄數據所在的頁,不需要進行第二次操作。
索引的建立規則
- 如果一個主鍵被定義了,那么這個主鍵就是作為聚集索引
- 如果沒有主鍵被定義,那么該表的第一個唯一非空索引被作為聚集索引
- 如果沒有主鍵也沒有合適的唯一索引,那么InnoDB內部會生成一個隱藏的主鍵作為聚集索引,這個隱藏的主鍵是一個6個字節的列,改列的值會隨著數據的插入自增
輔助索引
輔助索引,也叫做非聚集索引,葉節點不包含行的全部數據。除了包含關鍵字外,還包含了一個標記,這個標記用來告訴InnoDB引擎從哪里可以找到與索引相對應的行數據。由于InnoDB引擎是索引組織表,因此,這個標記就是相應的行數據的聚集索引關鍵字。
輔助索引的存在并不影響數據在聚集索引中的組織,因此一個表可以有多個輔助索引。
使用輔助索引查找一條表記錄的過程:通過輔助索引查找到對應的關鍵字,最后在聚集索引中使用關鍵字獲取對應的行記錄,這也是通常情況下行記錄的查找方式。
使用建議
聚集索引的優先選擇列
不建議的聚集索引列
規范與建議
回表
先了解一個概念,MySQL對 WHERE 中條件的處理,根據索引使用情況分成三種:index key, index filter, table filter
1. index key
用于確定SQL查詢在索引中的連續范圍(起始范圍+結束范圍)的查詢條件,被稱之為Index Key。由于一個范圍,至少包含一個起始與一個終止,因此Index Key也被拆分為Index First Key和Index Last Key,分別用于定位索引查找的起始,以及索引查詢的終止條件。
2. index filter
在使用 index key 確定了起始范圍和介紹范圍之后,在此范圍之內,還有一些記錄不符合 WHERE 條件,如果這些條件可以使用索引進行過濾,那么就是 index filter。
3. table filter
WHERE 中的條件不能使用索引進行處理的,只能訪問table,進行條件過濾了。
從普通索引查出主鍵索引,然后查詢出數據的過程叫做回表。回表一次就會執行一次查詢,所以避免回表是減少數據庫壓力、提高效率的有效手段。在InnoDB中,使用聯合索引配合主鍵索引可以直接返回結果而不需要回表查詢。
聯合索引(復合索引)與前綴索引(最左原則)
Mysql從左到右的使用索引中的字段,一個查詢可以只使用索引中的一部份,但只能是最左側部分。例如索引是(a,b,c),可以支持 a | a,b | a,b,c 3種組合進行查找,但不支持 b,c 進行查找。這是最左原則的第一層意思:聯合索引的多個字段中,只有當查詢條件為聯合索引的第一個字段時,索引才會有效。
條件 WHERE a LIKE 'perfix%'; 索引也會有效。這是最左原則的第二層意思:根據字段值最左若干個字符進行的模糊查詢,索引有效。
覆蓋索引
覆蓋索引是對聯合索引的合理利用。
比如 SELECT a, b FROM table WHERE a = 'wangnima'; ,如果我們已經創建了(a)或(a,b)的聯合索引,那么這條語句會直接從索引返回而不會發生回表。即創建索引的字段覆蓋了查詢字段。
如果執行 SELECT c FROM table WHERE a = 'wangnima'; ,就會發生回表,因為我們的輔助索引樹中,沒有字段 c 的數據,需要拿到主鍵索引的關鍵字,去主鍵索引中回表查詢。
但是需要注意的是,索引雖好不可濫用。
索引下推(Index Condition Pushdown (ICP))
結合在 回表 概念中引出的三種索引使用情況(index key, index filter, table filter),ICP 技術,就是 index filter 技術。MySQL的架構分為服務器層和引擎層。
官方解釋(https://dev.mysql.com/doc/refman/5.6/en/index-condition-pushdown-optimization.html)
索引條件下推(ICP)是對MySQL使用索引從表中檢索行的情況的優化。如果沒有ICP,存儲引擎將遍歷索引以定位基表中的行,并將它們返回到MySQL服務器,該服務器將計算基表行的where條件。在啟用ICP的情況下,如果部分where條件可以通過只使用索引中的列來計算,MySQL服務器會把where條件的這部分 推入 存儲引擎。然后,存儲引擎通過使用索引條目來評估所推送的索引條件,并且只有在滿足該條件時才從表中讀取行。ICP可以減少存儲引擎必須訪問基本表的次數和MySQL服務器必須訪問存儲引擎的次數。
根據官方的指導,我們來做個驗證:
EXPLAIN SELECT * FROM people WHERE zipcode='95054' AND lastname LIKE '%lao%' AND address LIKE '%Main Street%';官方解釋:
EXPLAIN使用“索引條件下推”時,輸出顯示 Using index condition在 Extra列中。
假設一個表包含有關人員及其地址的信息,并且該表的索引定義為 INDEX (zipcode, lastname, firstname)。如果我們知道一個人的zipcode價值但不確定姓氏,我們可以這樣搜索:
SELECT * FROM people WHERE zipcode='95054' AND lastname LIKE '%etrunia%' AND address LIKE '%Main Street%';MySQL可以使用索引來掃描人 zipcode='95054'。第二部分(lastname LIKE '%etrunia%')不能用于限制必須掃描的行數,因此如果沒有Index Condition Pushdown,此查詢必須為所有擁有的人檢索完整的表行 zipcode='95054'。
使用索引條件下推,MySQL lastname LIKE '%etrunia%'在讀取整個表行之前檢查該 部分。這樣可以避免讀取與索引元組相對應的完整行,這些行匹配 zipcode條件而不是 lastname條件。
默認情況下啟用索引條件下推。可以optimizer_switch通過設置index_condition_pushdown標志來控制 系統變量 :
SET optimizer_switch = 'index_condition_pushdown=off'; SET optimizer_switch = 'index_condition_pushdown=on';實踐
*注意語句中的“[ ··· ]”中括號指代變量,書寫時記得去掉
普通索引
這是最基本的索引,它沒有任何限制。它有以下幾種創建方式:
1. 創建索引
CREATE INDEX indexName ON mytable(username(length));如果不是字符類型的字段,如int,則不要指定length;如果是CHAR,VARCHAR類型,length可以不指定,也可以小于字段實際長度;如果是BLOB和TEXT類型,必須指定 length。
2. 修改表結構(添加索引)
ALTER table tableName ADD INDEX indexName(columnName)3. 創建表的時候直接指定
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, INDEX [indexName] (username(length)) );唯一索引
它與前面的普通索引類似,不同的就是:索引列的值必須唯一,但允許有空值。如果是組合索引,則列值的組合必須唯一。它有以下幾種創建方式:
1. 創建索引
CREATE UNIQUE INDEX indexName ON mytable(username(length))2. 修改表結構
ALTER table mytable ADD UNIQUE [indexName] (username(length))3. 創建表的時候直接指定
CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, UNIQUE [indexName] (username(length)) );刪除索引的語法
DROP INDEX [indexName] ON mytable;總結
合理利用索引對于提升數據庫的性能、減輕數據庫服務器的負擔是最直接有效的手段。
其實,索引的本質就是通過縮小范圍、把隨機事件變成順序事件來篩選出最終結果,同時可以總是用同一種查找方式來定位數據,這樣就可以兼顧高效率和穩定性。
總結
以上是生活随笔為你收集整理的mysql 隐藏中间四位_MySQL知识体系——索引的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电商常用同义词库_【福利】不可错过的电商
- 下一篇: mysql数据库中的int类型_MySQ