MySQL資料庫:13、索引
目錄MySQL資料庫之索引
一、索引的概念
1、什麼是索引
1)索引就好比一本書的目錄,它能讓你更快的找到自己想要的內容
2)讓獲取的資料更有目的性,從而提高資料庫檢索資料的效能
2、索引的儲存型別
MySQL中索引的儲存型別有兩種,即 BTree 和 Hash。
3、索引的實現
索引是在儲存引擎中實現的。(MySQL 的儲存引擎有:InnoDB、MyISAM、Memory、Heap)
- InnoDB / MyISAM 只支援 BTree 索引
- Memory / Heap 都支援 BTree 和 Hash 索引
4、什麼是儲存引擎
儲存引擎就是指 表的型別 以及 表在計算機上的儲存方式。
5、索引的優缺點
-
優點:
- 提高資料的查詢的效率(類似於書的目錄)
- 可以保證資料庫表中每一行資料的唯一性(唯一索引)
- 減少分組和排序的時間(使用分組和排序子句進行資料查詢)
- 被索引的列會自動進行分組和排序
-
缺點:
- 佔用磁碟空間
- 降低更新表的效率(不僅要更新表中的資料,還要更新相對應的索引檔案)
二、索引的分類
1、普通索引 和 唯一索引
普通索引:MySQL 中的基本索引型別,允許在定義索引的列中插入 重複值 和 空值
唯一索引:要求索引列的值必須 唯一,但允許 有空值
如果是組合索引,則列值的組合必須 唯一
主鍵索引是一種特殊的唯一索引,不允許 有空值
2、單列索引 和 組合索引
單列索引:一個索引只包含單個列,一個表可以有多個單列索引
組合索引:在表的 多個欄位 組合上 建立的 索引
只有在查詢條件中使用了這些欄位的 左邊欄位 時,索引才會被使用(最左字首原則)
3、全文索引
全文索引 的型別為 fulltext
在定義索引的 列上 支援值的全文查詢,允許在這些索引列中插入 重複值 和 空值
全文索引 可以在 char、varchar 和 text 型別的 列 上建立
4、空間索引
空間索引 是對 空間資料型別 的欄位 建立的索引
MySQL中的空間資料型別有4種,分別是 Geometry、Point、Linestring 和 Polygon
MySQL 使用 Spatial 關鍵字進行擴充套件,使得能夠用建立正規索引類似的語法建立空間索引
建立空間索引的列,不允許為空值,且只能在 MyISAM 的表中建立。
5、字首索引
在 char、varchar 和 text 型別的 列 上建立索引時,可以指定索引 列的長度
三、索引加快查詢的本質
1、primary key
2、unique key
3、index key
1.上述的三個key都可以加快資料查詢
2.primary key和unique key除了可以加快查詢本身還自帶限制條件而index key很單一就是用來加快資料查詢
3.外來鍵不屬於索引鍵的範圍 是用來建立關係的 與加快查詢無關
id int primary key auto_increment,
name varchar(32) unique,
province varchar(32)
age int
phone bigint
select name from userinfo where phone=18818888888; # 一頁頁的翻
select name from userinfo where id=99999; # 按照目錄確定頁數找
索引可以加快資料查詢 但是會降低增刪的速度
通常情況下我們頻繁使用某些欄位查詢資料
為了提升查詢的速度可以將該欄位建立索引
聚集索引(primary key)
主鍵、主鍵索引
輔助索引(unique,index)
除主鍵意外的都是輔助索引,輔助索引其實本質上也是用的聚集索引的資料來查詢的(用的主鍵的資料)
覆蓋索引
select name from user where name='jason';
所謂覆蓋索引就是條件中的欄位名和檢視的欄位名稱相同
非覆蓋索引
select age from user where name='jason';
四、索引的結構
MySQL 索引 的資料結構可以分為 BTree 和 Hash 兩種,BTree 又可分為 BTree 和 B+Tree。
1、Hash:
hash:也可稱為‘二叉樹’
使用 Hash 表儲存資料,Key 儲存索引列,Value 儲存行記錄或行磁碟地址。
Hash 只支援等值查詢(“=”,“IN”,“<=>”),不支援任何範圍查詢(原因在於 Hash 的每個鍵之間沒有任何的聯絡),Hash 的查詢效率很高,時間複雜度為 O(1)。
2、BTree:
屬於多叉樹,又名多路平衡查詢樹。
MySQL的資料是儲存在磁碟檔案中的,查詢資料時需要先把磁碟中的資料載入到記憶體中,磁碟IO操作非常耗時,所以我們優化的重點就是儘量減少磁碟IO操作,所以,我們應當儘量減少從磁碟中讀取資料的次數。另外,從磁碟中讀取資料時,都是按照磁碟塊來讀取的,並不是一條一條的讀。如果我們能把儘量多的資料放進磁碟塊中,那一次磁碟讀取操作就會讀取更多資料,那我們查詢資料的時間也會大幅度降低。
如果我們用樹這種資料結構作為索引的資料結構,那我們每查詢一次資料就需要從磁碟中讀取一個節點,也就是我們說的一個磁碟塊。我們都知道平衡二叉樹可是每個節點只儲存一個鍵值和資料的。那說明什麼?說明每個磁碟塊僅僅儲存一個鍵值和資料!那如果我們要儲存海量的資料呢?
可以想象到二叉樹的節點將會非常多,高度也會極其高,我們查詢資料時也會進行很多次磁碟IO,我們查詢資料的效率將會極低!
為了解決平衡二叉樹的這個弊端,B樹應運而生, B樹是一種多叉平衡查詢樹,主要的特點是:
- BTree 的節點儲存多個元素( 鍵值 - 資料 / 子節點 的地址)
- BTree 節點的鍵值按 非降序 排列
- BTree 所有葉子節點都位於同一層(具有相同的深度)
下面模擬下查詢key為27的data的過程:
存在的一些問題:
- B樹中每個節點中包含key值以及data值,而每一個節點的儲存空間是有限的(MySQL預設16K),如果data中存放的資料較大時,將會導致每個節點能儲存的key的數量很小,所以當資料量很多,且每行資料量很大的時候,同樣會導致樹的高度變得很高,增大查詢時的磁碟IO次數,進而影響查詢效率。
- 不支援範圍查詢的快速查詢,而在實際的應用中,資料庫範圍查詢的頻率非常高,以下的一種情況是我查詢10和35之間的資料,查詢到15之後,需要回到根節點重新遍歷查詢,需要從根節點進行多次遍歷,查詢效率有待提高。
3、B+Tree:
只有葉子節點才會存放真正的資料 其他節點只存放索引資料
對比B樹和B+樹,我們發現二者主要存在以下幾點不同的地方:
- 資料都存放在葉子節點中
- 非葉子節點只儲存鍵值資訊,不再儲存資料
- 所有葉子節點之間都有一個指標,指向下一個葉子節點,而且葉子節點之間使用雙向指標連線,最底層的葉子節點形成了一個雙向有序連結串列
等值查詢
下面模擬下查詢key為9的data的過程:
範圍查詢
下面模擬下查詢key的範圍為9到26這個範圍的data的過程:
從上面的結果,我們可以知道B+樹作為索引結構帶來的好處:
- 磁碟IO次數更少
- 資料遍歷更為方便
- 查詢效能更穩定
由於B+樹優秀的結構特性,在MySQL中,儲存引擎MyISAM和InnoDB的索引就採用了B+樹的資料結構。
B*樹
B*葉子節點和枝節點都有指向其他節點的指標
ps:
- 輔助索引在查詢資料的時候最會還是需要藉助於聚集索引
- 輔助索引葉子節點存放的是資料的主鍵值
- 有時候就算採用索引欄位查詢資料 也可能不會走索引!!!
五、索引失效的情況
1.前導模糊查詢不能利用索引(like '%XX'或者like '%XX%')
2.如果mysql估計使用全表掃描要比使用索引快,則不使用索引
3.OR前後存在非索引的列,索引失效
如果條件中有or,即使其中有條件帶索引也不會使用(這也是為什麼儘量少用or的原因)
要想使用or,又想讓索引生效,只能將or條件中的每個列都加上索引
4.普通索引的不等於不會走索引;如果是主鍵,則還是會走索引;如果是主鍵或索引是整數型別,則還是會走索引
5.組合索引最左字首
如果組合索引為:(name,email)
name and email -- 使用索引
name -- 使用索引
email -- 不使用索引
6.is null可以使用索引,is not null無法使用索引
最好在設計表時設定NOT NULL約束,比如將INT型別的預設值設為0,將字串預設值設為''。
7.計算、函式導致索引失效另外一種情況
#使用到了索引
explain select * from student_info where name like 'li%';
#未使用索引,花費時間更久
explain select * from student_info where LEFT(name,2)='li';
擴充套件:
如果列型別是字串,那一定要在條件中將資料使用引號引用起來,否則不使用索引
#不會使用name的索引
explain select * from student_info where name=123;
#使用到索引
explain select * from student_info where name='123';
如上,name欄位是VARCAHR型別的,但是比較的值是INT型別的,name的值會被隱式的轉換為INT型別再比較,中間相當於有一個將字串轉為INT型別的函式。這也相當於是函式導致的索引失效。
8.字符集不統一
統一使用utf8mb4( 5.5.3 版本以上支援 ) 相容性更好,統一字符集可以避免由於字符集轉換產生的亂碼。不同的 字符集 進行比較前需要進行 轉換 會造成索引失效。。
ps:最好能記三個左右的特殊情況