MySql Innodb 索引有哪些與詳解

概述

對于MYSQL的INNODB存儲引擎的索引,大家是不陌生的,都能想到是 B+樹結構,可以加速SQL查詢。但對于B+樹索引,它到底“長”得什么樣子,它具體如何由一個個字節構成的,這些的基礎知識鮮有人深究。本篇文章從MYSQL行記錄開始說起,層層遞進,包括數據頁,B+樹聚簇索引,B+樹二級索引,最后在文章末尾給出MYSQL索引的建議。

表空間

首先,我們來了解一下 MySQL 的表空間。在 MySQL 中,所有的數據都被存儲在一個空間內,稱之為表空間,表空間內部又可以分為段(segment)、區(extent)、頁(page)、行(row),其邏輯結構如下圖:

段(segment)

表空間是由不同的段組成的,常見的段有:數據段,索引段,回滾段等等,在 MySQL 中,數據是按照 B+ 樹來存儲,因此數據即索引,因此數據段即為 B+ 樹的葉子節點,索引段為 B+ 樹的非葉子節點,回滾段用于存儲undo日志,用于事務失敗后數據回滾以及在事務未提交之前通過undo日志獲取之前版本的數據,在?InnoDB 1.1?版本之前,一個 InnoDB 只支持一個回滾段,支持 1023 個并發修改事務同時進行,在?InnoDB 1.2?版本,將回滾段數量提高到了 128 個,也就是說可以同時進行128 * 1023個并發修改事務。

區(extent)

區是由連續頁組成的空間,每個區的固定大小為 1MB,為保證區中頁的連續性,InnoDB 會一次從磁盤中申請 4 ~ 5 個區,在默認不壓縮的情況下,一個區可以容納 64 個連續的頁。但是在開始新建表的時候,空表的默認大小為 96KB,是由于為了高效的利用磁盤空間,在開始插入數據時表會先利用 32 個頁大小的碎片頁來存儲數據,當這些碎片使用完后,表大小才會按照 MB 倍數來增加。

頁(page)

頁是 InnoDB 存儲引擎的最小管理單位,每頁大小默認是 16KB,從?InnoDB 1.2.x?版本開始,可以利用innodb_page_size來改變頁大小,但是改變只能在初始化 InnoDB 實例前進行修改,之后便無法進行修改,除非mysqldump導出創建新庫,常見的頁類型有:數據頁、undo頁、系統頁、事務數據頁、插入緩沖位圖頁、插入緩沖空閑列表頁、未壓縮的二進制大對象頁以及壓縮的二進制大對象頁等。

行(row)

行對應的是表中的行記錄,每頁存儲最多的行記錄也是有硬性規定的最多16KB/2-200,即 7992 行,其中 16KB 是頁大小。

Clustered Index 聚簇索引

MySQL InnoDB 引擎具有強制聚簇索引,通常使用主鍵。也就是主鍵就是Clustered Index,如果沒有主鍵按以下規則生成。

Clustered Index 條件優化級:
  1. 表有明確的PRIMARY KEY:使用PRIMARY KEY

  2. 無PRIMARY KEY:InnoDB 默認使用第一個 UNIQUE INDEX,且索引列需要全部定義為非空列(NOT NULL)作為Clustered Index

  3. 如無PRIMARY KEY,也沒有合適的UNIQUE INDEX,InnoDB將會在包含行ROW ID的合成列上生成一個名為GEN_CLUST_INDEX的隱藏Clustered Index

ROW ID:ROW ID是6 byte字段,由InnoDB分配,用于行排序。插入新行而單調增加,在物理上插入按ROW ID順序排列

注:UNIQUE INDEX 包含的列需要全部定義為NOT NULL非空,才會被當做Clustered Index

MyISAM 存儲引擎不支持聚簇索引并且一直使用堆表

2. 聚簇索引如何加速查詢

通過聚簇索引訪問行很快,因為索引搜索直接指向包含行數據的頁面。如果表很大,與使用與索引記錄不同的頁來存儲行數據的存儲組織相比,聚簇索引架構通常可以節省磁盤 I/O 操作。

3. Clustered Index 示例及查詢:

INNODB_INDEXES 表type字段說明:

  • 0 = 非唯一索引的二級索引 :nonunique secondary index;

  • 1 = 自動生成的聚簇索引:automatically generated clustered index (GEN_CLUST_INDEX);

  • 2 = 唯一索引(非聚簇索引): unique nonclustered index;

  • 3 = 聚簇索引 clustered index;

  • 32 = 全文索引 full-text index

不同MySQL版本表名不同,使用命令查詢:SHOW TABLES FROM INFORMATION_SCHEMA LIKE 'INNODB_%';

自動生成名為GEN_CLUST_INDEX的Clustered Index示例:

-- 創建無主鍵、無唯一索引 
CREATE TABLE `clustered_index_demo` (`id` int DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;-- 查詢表索引 
-- 如5.7以下版本表名不同,使用命令查詢:SHOW TABLES FROM INFORMATION_SCHEMA LIKE 'INNODB_SYS%';
SELECT t2.INDEX_ID ,t2.`NAME` , t2.TABLE_ID , t2.`TYPE` , t2.N_FIELDS , t2.PAGE_NO , t2.`SPACE` , t2.MERGE_THRESHOLD
FROM information_schema.INNODB_TABLES t1 
INNER JOIN information_schema.INNODB_INDEXES t2 ON t1.TABLE_ID = t2.TABLE_ID
WHERE t1.`NAME` = 'wiki/clustered_index_demo';-- 查詢結果| INDEX_ID | NAME            | TABLE_ID | TYPE | N_FIELDS | PAGE_NO | SPACE | MERGE_THRESHOLD |
|----------|-----------------|----------|------|----------|---------|-------|-----------------|
|     3616 | GEN_CLUST_INDEX |     3276 |    1 |        5 |       4 |  2113 |  
增加包含NOT NULL列的唯一索引示例:

Tips : 修改表結構,InnoDB將刪除原自動生成的GEN_CLUST_INDEX索引

-- 增加兩列
ALTER TABLE `wiki`.`clustered_index_demo`
ADD COLUMN `username` varchar(32) NOT NULL,
ADD COLUMN `name` varchar(64) NOT NULL;
-- 增加唯一索引 
ALTER TABLE `wiki`.`clustered_index_demo`
ADD UNIQUE INDEX `IDX_UNIQUE` (`username`,`name`) USING BTREE;| INDEX_ID | NAME       | TABLE_ID | TYPE | N_FIELDS | PAGE_NO | SPACE | MERGE_THRESHOLD |
|----------|------------|----------|------|----------|---------|-------|-----------------|
|     3620 | IDX_UNIQUE |     3278 |    3 |        5 |       4 |  2115 |              50 |
唯一索引包含NULL列
-- 將唯一索引,其中一列改為NULL, Clustered Index將被刪除,重新生成GEN_CLUST_INDEX
ALTER TABLE `wiki`.`clustered_index_demo`
CHANGE `username` `username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
CHANGE `name` `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL;| INDEX_ID | NAME            | TABLE_ID | TYPE | N_FIELDS | PAGE_NO | SPACE | MERGE_THRESHOLD |
|----------|-----------------|----------|------|----------|---------|-------|-----------------|
|     3625 | GEN_CLUST_INDEX |     3281 |    1 |        6 |       4 |  2118 |              50 |
|     3626 | IDX_UNIQUE      |     3281 |    2 |        3 |       5 |  2118 |      

查詢所有自動生成的Clustered Index

SELECTi.TABLE_ID,t.NAME
FROMinformation_schema.INNODB_INDEXES iJOIN information_schema.INNODB_TABLES t ON (i.TABLE_ID = t.TABLE_ID)
WHEREi.NAME = 'GEN_CLUST_INDEX';| TABLE_ID | NAME                      |
|----------|---------------------------|
|     3281 | wiki/clustered_index_demo |

?輔助索引

除了聚簇索引之外的索引都可以稱之為輔助索引,與聚簇索引的區別在于輔助索引的葉子節點中存放的是主鍵的鍵值。一張表可以存在多個輔助索引,但是只能有一個聚簇索引,通過輔助索引來查找對應的航記錄的話,需要進行兩步,第一步通過輔助索引來確定對應的主鍵,第二步通過相應的主鍵值在聚簇索引中查詢到對應的行記錄,也就是進行兩次 B+ 樹搜索。相反,通過輔助索引來查詢主鍵的話,遍歷一次輔助索引就可以確定主鍵了,也就是所謂的索引覆蓋,不用回表。

創建輔助索引,可以創建單列的索引,也就是用一個字段來創建索引,也可以用多個字段來創建副主索引稱為聯合索引,創建聯合索引后,B+ 樹的節點存儲的鍵值數量不是 一個,而是多個,如下圖:

  • 聯合索引的 B+ 樹和單鍵輔助索引的 B+ 樹是一樣的,鍵值都是排序的,通過葉子節點可以邏輯順序的讀出所有的數據,比如上圖所存儲的數據時,按照(a,b)這種形式(1,1),(1,2),(2,1),(2,4),(3,1),(3,2)進行存放,這樣有個好處,那就是存放數據時排序了,當進行order by對某個字段進行排序時,可以減少復雜度,加速進行查詢;

  • 當用select * from table where a=? and ?可以使用索引(a,b)來加速查詢,但是在查詢時有一個原則,SQL 的where條件的順序必須和二級索引一致,而且還遵循索引最左原則,select * from table where b=?則無法利用(a,b)索引來加速查詢。

  • 輔助索引還有一個概念便是索引覆蓋,索引覆蓋的一個好處便是輔助索引不包含行記錄,因此其大小遠遠小于聚簇索引,利用輔助索引進行查詢可以減少大量的 IO 操作。

索引的優缺點及建議

?

優點:

  1. 對于等值查詢,可快速定位到對于的行記錄。

  2. 對于范圍查詢,可輔助縮小掃描區間。

  3. 當ORDER BY的列名 與 索引的列名完全一致時,可加快排序的順序。

  4. 當GROUP BY的列名 與 索引的列名完全一致時,可加快分組。

  5. 當二級索引列中 包含了 SELECT 關鍵字后面寫明的所有列,則在查詢完成二級索引之后無需進行回表操作,直接返回即可。這種情況,稱為【覆蓋索引】。

缺點:

建立索引占用磁盤空間。

對表中的數據進行 增加,刪除,修改 操作時,都需要修改各個索引樹,特別是如果新增的行記錄的主鍵順序不是遞增的,就會產生頁分裂,頁回收等操作,有較大的時間成本。

當二級索引列的值 的 不重復值的個數較少時,通過二級索引查詢找到的數據量就會比較多,相應的就會產生過多的回表操作。

在執行查詢語句的時候,首先要生成一個執行計劃。通常情況下,一個SQL在執行過程中最多使用一個二級索引,在生成執行計劃時需要計算使用不同索引執行查詢時所需的成本,最后選擇成本最低的那個索引執行查詢。因此,如果建立太多的索引,就會導致成本分析過程耗時太多,從而影響查詢語句的性能。

建議:

  1. 只為用于搜索,排序,分組的列創建索引。

  2. 索引的列需要有辨識性,盡可能地區分出不同的記錄。

  3. 索引列的類型盡量小。因為數據類型越小,索引占用的存儲空間就越少,在一個數據頁內就可以存放更多的記錄,磁盤I/O帶來的性能損耗也就越小。

  4. 如果需要對很長的字段進行快速查詢,可考慮為列前綴建立索引。【alter table table_M add index idx_key1(column_n(10)) --> ?將table_M表的 idx_key1列的前10個字符創建索引】

  5. 覆蓋索引,當二級索引列中包含了SELECT關鍵字后面寫明的所有列,則在查詢完成二級索引之后無需進行回表操作,直接返回即可。因此,編寫【select *】的時候,要想想是否必要

  6. 在查詢語句中,索引列不要參與條件值計算,也是把條件值計算完成之后,再和索引列對比。【否則MYSQL會認為搜索條件不能形成合適的掃描區間來減少掃描的記錄數量】

?

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/38797.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/38797.shtml
英文地址,請注明出處:http://en.pswp.cn/web/38797.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Spring Boot】JPA 的查詢方式

JPA 的查詢方式 1.使用約定方法名2.用 JPQL 進行查詢3.用原生 SQL 進行查詢3.1 根據 ID 查詢用戶3.2 查詢所有用戶3.3 根據 email 查詢用戶3.4 根據 name 查詢用戶,并返回分頁對象 Page3.5 根據名字來修改 email 的值3.6 使用事務 4.用 Specifications 進行查詢5.用…

Mac視頻下載工具,兼容14系統,Downie 4軟件下載

Downie 4 是一款由James Application開發的視頻下載軟件,支持Mac操作系統。該軟件允許用戶從各種視頻網站上下載視頻內容,以便于在本地設備上觀看,無需依賴互聯網連接。自動下載:可以設置Downie 4自動下載指定網站上的視頻&#x…

當+=的時候,為什么會出現NaN?

問: var textToDisplay; // "testing"; textToDisplay "testing"; textToDisplay 1; var someNumber 1; var oneMoreNumber; oneMoreNumber textToDisplay someNumber; //results in NaN console.log(oneMoreNumber); 這里的結果是NaN? 回答: 是…

【LinuxC語言】線程池的原理和實現

文章目錄 前言為什么需要線程池線程池的原理總結前言 在現代計算中,多線程編程已經成為一種常見的做法,它可以幫助我們更有效地利用多核處理器的能力。然而,頻繁地創建和銷毀線程會帶來一定的開銷。為了解決這個問題,我們可以使用一種稱為“線程池”的技術。線程池是一種在…

黑馬點評-Redis的緩存擊穿,緩存雪崩,緩存穿透,互斥鎖,邏輯過期

文章目錄 1.緩存穿透2.緩存雪崩3.緩存擊穿3.1 互斥鎖3.2 基于邏輯過期 1.緩存穿透 解決辦法 寫入NULL值到Redis緩存,以后就會命中Redis的控制緩存而不會出現請求直接打到數據庫的問題! 代碼 2.緩存雪崩 這個概念很好理解,雪崩就是無數的…

【LLM大模型書】從零開始大模型開發與微調:基于PyTorch與ChatGLM (附PDF)

今天又來給大家推薦一本大模型方面的書籍<從零開始大模型開發與微調&#xff1a;基于PyTorch與ChatGLM>。 本書使用PyTorch 2.0作為學習大模型的基本框架&#xff0c;以ChatGLM為例詳細講解大模型的基本理論、算法、程序實現、應用實戰以及微調技術&#xff0c;為讀者揭…

設備樹在Linux系統的屬性

設備樹源文件 設備樹源文件擴展名為.dts&#xff0c;我們在前面移植 Linux 的時候卻一直在使用.dtb 文件&#xff0c;那么 DTS 和 DTB 這兩個文件是什么關系呢&#xff1f; DTS 是設備樹源碼文件&#xff0c; DTB 是將 DTS 編譯以后得到的二進制文件。將.dts 編譯為.dtb 需要什…

【微信小程序開發實戰項目】——如何制作一個屬于自己的花店微信小程序(2)

&#x1f468;?&#x1f4bb;個人主頁&#xff1a;開發者-曼億點 &#x1f468;?&#x1f4bb; hallo 歡迎 點贊&#x1f44d; 收藏? 留言&#x1f4dd; 加關注?! &#x1f468;?&#x1f4bb; 本文由 曼億點 原創 &#x1f468;?&#x1f4bb; 收錄于專欄&#xff1a…

FreeRTOS和UCOS操作系統使用筆記

FreeRTOS使用示例 UCOS使用示例 信號量使用 信號量訪問共享資源區/ OS_SEMMY_SEM; //定義一個信號量&#xff0c;用于訪問共享資源OSSemCreate ((OS_SEM* )&MY_SEM, //創建信號量&#xff0c;指向信號量(CPU_CHAR* )"MY_SEM", //信號量名字(OS_SEM_CTR )1, …

軟件模型分類及特點

在軟件開發的世界里&#xff0c;我們經常會遇到業務模型、系統模型和軟件模型這三個層次。這些模型各有特點&#xff0c;相互之間也有著緊密的聯系。通過理解這三個層次之間的映射關系&#xff0c;我們能更好地理解和掌握軟件開發的全過程 1. 業務模型 業務模型描述了組織的業…

政務單位網站SSL證書選擇策略

在數字化快速發展的今天&#xff0c;政務單位網站作為政府與公眾溝通的重要橋梁&#xff0c;其安全性和可信度顯得尤為重要。SSL證書作為保障網站安全的重要手段&#xff0c;其選擇對于政務單位網站來說至關重要。本文將探討政務單位網站在選擇SSL證書時應該考慮的因素&#xf…

如何使用python網絡爬蟲批量獲取公共資源數據教程?

原文鏈接&#xff1a;如何使用python網絡爬蟲批量獲取公共資源數據教程&#xff1f;https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247608240&idx4&snef281f66727afabfaae2066c6e92f792&chksmfa826657cdf5ef41571115328a09b9d34367d8b11415d5a5781dc4c…

【AI提升】如何使用大模型:本機離線和FastAPI服務調用

大模型本身提供的功能&#xff0c;類似于windows中的一個exe小工具&#xff0c;我們可以本機離線調用然后完成具體的功能&#xff0c;但是別的機器需要訪問這個exe是不可行的。常見的做法就是用web容器封裝起來&#xff0c;提供一個http接口&#xff0c;然后接口在后端調用這個…

KV260視覺AI套件--PYNQ-DPU-Resnet50

目錄 1. 簡介 2. 代碼解析 3. 全部代碼展示 4. 總結 1. 簡介 本文以 Resnet50 為例&#xff0c;展示使用 PYNQ 調用 DPU 運行 Resnet50 網絡的詳細過程&#xff0c;并對其中關鍵代碼做出解釋。 PYNQ是一個針對Xilinx Zynq平臺的Python開發框架&#xff0c;它允許開發者使…

KEYSIGHT是德科技 E5063A ENA 系列網絡分析儀

E5063A ENA 矢量網絡分析儀 18GHz 2端口 降低無源射頻元器件的測試成本 Keysight E5063A ENA 是一款經濟適用的臺式矢量網絡分析儀&#xff0c;可用于測試簡單的無源元器件&#xff0c;例如頻率最高達到 18 GHz 的天線、濾波器、電纜或連接器。 作為業界聞名的 ENA 系列…

深入解析 Laravel 事件系統:架構、實現與應用

Laravel 的事件系統是框架中一個強大且靈活的功能&#xff0c;它允許開發者在應用程序中定義和使用自定義事件和監聽器。這個系統基于觀察者模式&#xff0c;使得代碼解耦和可維護性大大提高。在本文中&#xff0c;我們將深入探討 Laravel 事件系統的工作原理、如何實現自定義事…

python @裝飾器的用法

裝飾器&#xff08;decorators&#xff09;是 Python 中的一種高級特性&#xff0c;它允許開發者修改函數或方法的行為&#xff0c;而不改變其定義。裝飾器通常用于日志記錄、權限檢查、性能測量等場景。裝飾器是通過在函數定義的前一行加上 decorator_name 來使用的。 基本用…

Qt簡單文本查找

Qt版本&#xff1a; Qt6 具體代碼&#xff1a; 1. 頭文件 mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>class QLineEdit; class QDialog; class QPushButton; class QVBoxLayout; class QTextEdit;QT_BEGIN_NAMESPACE namespace Ui…

為什么AI算法工程師要求C++?

在開始前剛好我有一些資料&#xff0c;是我根據網友給的問題精心整理了一份「c&#xff0b;&#xff0b;的資料從專業入門到高級教程」&#xff0c; 點個關注在評論區回復“666”之后私信回復“666”&#xff0c;全部無償共享給大家&#xff01;&#xff01;&#xff01;能跑出…

找到字符串中所有子串出現的位置python

直接find干就完了。 如果你希望找到字符串中所有子串出現的位置&#xff0c;而不僅僅是一個位置&#xff0c;你可以通過循環查找并收集所有起始位置。以下是修改后的代碼&#xff1a; def find_all_substring_positions(string, substring): positions [] # 用于存儲所有…