Mysql 索引精講

来源:https://www.cnblogs.com/weilingfeng/archive/2019/05/10/10845973.html
-Advertisement-
Play Games

Mysql 索引精講 開門見山,直接上圖,下麵的思維導圖即是現在要講的內容,可以先有個印象~ 常見索引類型(實現層面) 索引種類(應用層面) 聚簇索引與非聚簇索引 覆蓋索引 最佳索引使用策略 1.常見索引類型(實現層面) 首先不談Mysql怎麼實現索引的,先馬後炮一下,如果讓我們來設計資料庫的索引, ...


 

Mysql 索引精講

開門見山,直接上圖,下麵的思維導圖即是現在要講的內容,可以先有個印象~

 

  • 常見索引類型(實現層面)
  • 索引種類(應用層面)
  • 聚簇索引與非聚簇索引
  • 覆蓋索引
  • 最佳索引使用策略

1.常見索引類型(實現層面)

首先不談Mysql怎麼實現索引的,先馬後炮一下,如果讓我們來設計資料庫的索引,該怎麼設計?

我們首先思考一下索引到底想達到什麼效果?其實就是想能夠實現快速查找數據的策略,所以索引的實現本質上就是一個查找演算法。

但是跟普通的查找有所不同,因為我們的數據有一下特征:

1.存儲的數據是非常非常多的
2.並且還不斷的動態變化

所以實現索引時需要考慮到這兩個特點。我們需要找一個最合適的數據結構演算法來實現查找功能。

下麵一起看下常見的查找策略,如下圖:

 

 

由於前面說的兩個特點我們首先排除靜態查找的演算法。

至於查找樹,我們有二叉樹和多叉樹兩種選擇:

二叉樹:如果選擇二叉樹的話,由於我們的數據量龐大,二叉樹的深度會變得非常大,我們的索引樹會變成參天大樹,每次查詢會導致很多磁碟IO。

多叉樹:多叉樹解決了了樹的深度大的問題,那麼我們到底選擇B樹還是B+樹呢?

B樹 摘自維基百科 zh.wikipedia.org/wiki/B%2B樹

 

 

B+樹 摘自維基百科 zh.wikipedia.org/wiki/B%2B樹

 

 

從上面圖可知B+樹的葉子節點存放了所有的索引值,並且葉子結點之間以鏈表的形式相互關聯,所以我們只需從最左的鏈表遍歷的話即可查找所有的值,最常見的用途就是範圍查找,而B樹則不滿足這範圍查找,又或者說實現特別複雜,所以Mysql最終選擇了使用B+樹實現這一功能。

1.1 B-Tree 索引(B+樹)

先說明一下,雖然叫在Mysql官方叫做B-Tree索引,但採用的是B+樹數據結構。

B-tree索引能夠加快訪問數據的速度,不需要進行全表掃描,而是從索引樹的根節點層層往下搜索,在根節點存放了索引值和指向下一個節點的指針。

下麵看下單列索引的數據怎麼組織的。

create table User(
`name` varchar(50) not null,
`uid` int(4) not null,
`gender` int(2) not null,
 key(`uid`)
);

複製代碼

上面User 表給uid列創建了一個索引,那麼往表裡插入uid(96~102)的時候存儲引擎是怎麼管理索引的呢?看下麵的索引樹

 

 

1.在葉子節點存放所有的索引值,非葉子節點值是為了更快定位包含目標值的葉子節點

2.葉子節點的值是有序的

3.葉子節點之間以鏈表形式關聯

下麵在看一下多列(聯合)索引的數據怎麼組織的。

create table User(
`name` varchar(50) not null,
`uid` int(4) not null,
`gender` int(2) not null,
 key(`uid`,`name`)
);

複製代碼

給User 表創建了聯合索引 key(uid,name) 這種情況下他的索引樹是如下圖所示。

 

 

特點跟單列索引一樣,不同之處在於他的排序,如果第一個欄位相同時會按第二個索引欄位排序

如何通過B-tree快速查找數據?

 

 

對於InnoDb 存儲引擎的B-tree索引,會按一下步驟通過索引找到行數據

  • 如果使用了聚簇索引(主鍵),則葉子節點上就包含行數據,可直接返回
  • 如果使用了非聚簇索引(普通索引),則在葉子節點存了主鍵,再根據主鍵查詢一次上面 的聚簇索引,最後返回數據

對於MyISAM 存儲引擎的B-tree索引,會按一下步驟通過索引找到行數據

  • 在MyISAM 的索引樹的葉子節點上除了索引值之外即沒存儲主鍵,也沒存儲行數據,而是存了指向行數據的指針,根據這個指針在從表文件查詢數據。

1.2 Hash 索引(哈希表)

哈希索引是基於哈希表來實現的,只有精確匹配所有的所有列才能生效。

也就是說假設有個hash索引 key (col1,col2) 那麼每次只有 col1和col2兩個欄位都用才能夠生效。因為生成hash索引的時候是根據一個hash函數對所有的索引列取hash值來實現的。

如下方圖,有個hash索引key(name)

 

 

當我們執行 mysql> select * from User where name='張三'; 時怎麼利用hash索引快速查找的?

  1. 第一步,計算出hash值,hash(張三) = 1287
  2. 第二步,定位行號,比如key=1287 對應的行號為3
  3. 第三步,找到指定行並且比較name列值是否為張三做個校驗

 

 


2.常見索引種類(應用層面)

主鍵索引

create table User(
`name` varchar(50) not null,
`uid` int(4) not null,
`gender` int(2) not null,
 primary key(`uid`)
);
複製代碼

主鍵索引是唯一的,通常以表的ID設置為主鍵索引,一個表只能有一個主鍵索引,這是他跟唯一索引的區別。

唯一索引

create table User(
`name` varchar(50) not null,
`uid` int(4) not null,
`gender` int(2) not null,
 unique key(`name`)
);
複製代碼

唯一索引主要用於業務上的唯一約束,他跟主鍵索引的區別是,一個表可以有多個唯一索引

單列索引

create table User(
`name` varchar(50) not null,
`uid` int(4) not null,
`gender` int(2) not null,
 key(`name`)
);
複製代碼

以某一個欄位為索引

聯合索引

create table User(
`name` varchar(50) not null,
`uid` int(4) not null,
`gender` int(2) not null,
 key(`name`,`uid`)
);
複製代碼

兩個或兩個以上欄位聯合組成一個索引。使用時需要註意滿足最左匹配原則!

還有其他不常用的就不介紹了~


3.聚簇索引與非聚簇索引

什麼是聚簇索引?
聚簇索引指的是他的 索引和行數據 在一起存儲。也就是在一顆B+樹的葉子結點上存儲的不僅是他的索引值,還有對應的某一行的數據。待會兒看圖便知。

聚簇索引不是一種索引,而是一種數據存儲組織方式 !!!

crreate table test(
  col1 int not null,
  col2 int not null,
  PRIMARY KEY(col1),
  KEY(col2)
);

複製代碼

如上所示,表test 由兩個索引,分別是主鍵 col1 和 普通索引 col2。那麼這倆索引跟聚簇非聚簇有啥關係呢?

會生成一個聚簇索引和一個非聚簇索引(二級索引),也就是說會組織兩個索引樹。主鍵索引會生成聚簇索引的樹 以及以col2為索引的非聚簇索引的樹。

InnoDb 將通過主鍵來實現聚簇索引 ,如果沒有主鍵則會選選一個唯一非空索引來實現。如果沒有唯一非空索引則會隱式生成一個主鍵。

下麵看下聚簇索引和非聚簇索引在索引樹上數據是怎麼分佈的,圖片摘自《高性能Nysql》

下圖是聚簇索引的數據組織方式。 col1為主鍵索引的聚簇索引樹

索引列是主鍵 col1

可以看出葉子結點除了存儲索引值 列col1 (3~99~4700)值 之外還存儲了其他列的值,如列col2 (92~8~13),如果還有別的列的話也會存儲,或者換句話說聚簇索引樹 在葉子節點上存儲某個索引值對應的一行數據。

 

下圖是非聚簇索引(二級索引)的數據組織方式。

索引列是 col2

 

 

與聚簇索引不同的是非聚簇索引在索引樹葉子節點上除了索引值之外只存了主鍵值。而聚簇索引則存了一行數據。

假如有一條sql 語句 select * from test where col2=93;
上面這條語句會經歷兩次從索引樹查找過程

1.第一步從非聚簇索引的索引樹上找到包含col2=93的葉子節點,並定位到行的主鍵 3
2.第二步 根據主鍵 3 在從聚簇索引定位包含 主鍵=3的葉子節點並返回全部行數據。

以上說的都是基於InnoDb存儲引擎的,MyISAM是不支持聚簇索引的,因為他的數據文件和索引文件是相互獨立存儲的 MyISAM存儲引擎的索引樹的葉子節點不會寸主鍵值,而存一個指向對應行的地址或者說是指針,然後再從表數據文件里去找,如下麵圖所示。

 

 

結論:

  • 聚簇索引:
    通常由主鍵或者非空唯一索引實現的,葉子節點存儲了一整行數據

  • 非聚簇索引:
    又稱二級索引,就是我們常用的普通索引,葉子節點存了索引值和主鍵值,在根據主鍵從聚簇索引查

4.覆蓋索引

覆蓋索引就是指索引包含了所有需要查詢的欄位。

create table User(
`name` varchar(50) not null,
`uid` int(4) not null,
`gender` int(2) not null,
 key(`uid`,`name`)
);

複製代碼

假如表 User有三個欄位 User (name,uid,gender),且有個聯合索引 key(name,uid)那麼 執行如下麵這條sql查詢時就用到了 覆蓋索引。

select name,uid from User where name in ('a','b') and uid >= 98 and uid <=100 ;

上面這條sql語句使用了聯合索引 key(name,uid),並且只需查找 name,uid兩個欄位,所以使用了覆蓋索引。覆蓋索引有什麼好處呢?先看一下下麵這個圖


上面這個圖就是 聯合索引key(name,uid) 所對應的索引樹,從圖中可以看出,如果我們只需查詢(name,uid)兩個欄位的話,從索引樹就能得到我們需要查的數據。不需要找到索引值之後再從表數據文件定位對應的行數據了。

 

覆蓋索引好處
1.避免了對主鍵索引(聚簇)的二次查詢
2.由於不需要回表查詢(從表數據文件)所以大大提升了Mysql緩存的負載

總之大大提升了讀取數據的性能


5.最佳索引使用策略

最後在講講使用索引過程中的避坑指南

獨立的列

獨立的列不是指單列索引,而是指索引列不能是表達式的一部分或者是函數的一部分

select * FROM test where col1 + 1 =100; // 不能是表達式一部分

select * FROM test where ABS(col1) =100; // 不能是函數一部分

最左匹配原則

假如有個聯合索引 key (col1,col2)。那麼以下查詢是索引無效的

select * from test where col2 = 3;

select * from test where col1 like '%3';

對於最左匹配原則,大家想一下B+樹的葉子節點的關聯就差不多知道為啥需要最左匹配原則了,因為B+的葉子結點,從左到右以鏈表的形式關聯的,索引我們查詢的時候要麼範圍查詢,要麼有明確的左邊一個開始的索引值,不能跳過或者不明確如 like '%XYZ'這種查詢。

索引值不能是null值

單列索引有null值會導致索引無效
多列索引只要有個列有null值會導致索引無效

使用聚簇索引和覆蓋索引大大提升讀取性能

因為聚簇索引和覆蓋索引的索引樹上就有了需要的欄位,所以不需要回表文件查詢,所以提升了查詢速度

使用短索引
如果很長的字元串進行查詢,只需匹配一個首碼長度,這樣能夠節省大量索引空間


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 安裝補丁KB2685811、重啟。 ...
  • 1、根據之前一篇關於rsync的隨筆部署好rsync服務後,可以開始inotify的部署 2、inotify的部署使用 ①、檢查系統是否支持inotify 如果出現上面結果說明系統支持inotify。 ②、安裝 ③、inotify參數 * 說明: max_user_instances:每個用戶創建i ...
  • rysnc server端 1、vim /etcrsyncd.conf (用戶rsync,目錄,模塊,非系統虛擬用戶及密碼文件) 2、創建共用目錄 /data/www/{www,bbs,blog} 3、創建rsync用戶,並授權訪問/data/www/ 4、創建密碼文件,複製配置文件里的路徑,然後添 ...
  • 眾所周知,在sqlserver中,表變數最大的特性之一就是沒有統計信息,無法較為準備預估其數據分佈情況,因此不適合參與較為複雜的SQL運算。當SQL相對簡單的時候,使用表變數,在某些場景下,即便是對錶變數的預估沒有產生偏差的情況下,仍舊會有問題。sqlserver的優化引擎對於表變數的支持十分不友好 ...
  • 一篇瞭解大數據架構及Hadoop生態圈 閱讀建議,有一定基礎的閱讀順序為1,2,3,4節,沒有基礎的閱讀順序為2,3,4,1節。 第一節 集群規劃 大數據集群規劃(以CDH集群為例),參考鏈接: https://www.cloudera.com/documentation/enterprise/la ...
  • Oracle Database 介紹 Oracle Database又名Oracle RDBMS簡稱Oracle是甲骨文公司的一款關係資料庫管理系統。 Oracle網站地址。 ...
  • redis簡介,redis數據結構中字元串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)的基礎命令 ...
  • --資料庫、模式、表名 "identities"."Test"."tab_test" --修改欄位名 ALTER TABLE "identities"."Test"."tab_test" RENAME "u_name" to realname ; --添加欄位 ALTER TABLE "identi... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...