1. 程式人生 > 其它 >MySQL資料庫:13、索引

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:最好能記三個左右的特殊情況