【MySQL篇】索引特性,索引的工作原理以及索引的創建與管理

目錄

一,初識索引

二,MySQL與磁盤交互的基本單位

?三,MySQL中數據文件的特性

四,理解page和索引

?五,聚簇索引和非聚簇索引

六,索引操作

查詢索引

創建主鍵索引

唯一索引的創建

普通索引的創建?

全文索引的創建

刪除索引

索引創建原則?


一,初識索引

MySQL索引類似于書籍的索引(目錄),每個書籍都有目錄,通過目錄可以快速定位到要查找的頁。

MySQL索引是一種數據結構,用于加快數據庫查詢的速度和性能。

索引能夠顯著提高查詢的速度,尤其是在大型表中進行搜索時。通過使用索引,MySQL可以直接定位到滿足條件的數據行,不需要遍歷整個表。

但是查詢速度的提高,同時是以插入,更新,和刪除的速度為代價的,這些寫操作,增加了大量的IO。所以它的價值,在于提高一個海量數據的檢索速度。

常見的索引分類:

  • 主鍵索引(primary key)
  • 唯一鍵索引(unique)
  • 普通 索引(index)
  • 全文索引(fulltext)

二,MySQL與磁盤交互的基本單位

MySQL在應用層給用戶提供存儲服務,用戶可以 進行CURD操作,而存儲 的都是數據,數據在磁盤這個外設中。磁盤是計算機的一個機械設備,相比于計算機其他電子元件,磁盤效率是比較低的。我們平時對表的操作 ,都是需要進行IO的。

我們知道,操作系統和磁盤交互(IO)的基本單位是4KB。而MySQL作為一款應用層軟件,可以想象成 一種特殊的文件系統。它有著更高的IO場景,所以,為了提高基本的IO效率,MySQL和磁盤進行數據交互的基本單位是16KB(存儲引擎為Innodb)。這個基本數據單元,在MySQL中叫做page。

?

?三,MySQL中數據文件的特性

MySQL中的數據文件,是以page為單位保存在磁盤上的。

MySQL的CURD操作,都是需要計算的,找到對應的插入位置,找到對應要修改或者查詢的數據。

而只要涉及到計算,就需要CPU的參與,而為了便于CPU的參與,一定要先將數據移到內存中。

所以再特定時間內,數據一定是磁盤中有,內存中也有。后序操作完內存數據之后,以特點的刷新策略,刷新的磁盤上。而這時就涉及 到磁盤和內存的數據交互,也就是IO了。此時IO的基本單位是page。

為了更好的進行上面的操作,MySQL服務器在內存中運行的時候,在服務器內部,就申請了Buffer pool的大內存空間,來進行各種緩存。其實就是很大的空間,來和磁盤進行IO交互。

在Innodb存儲引擎下,Buffer pool的大小為128M。MySQL需要自己對這部分空間進行管理。

為了更高的效率,一定要盡可能的減少系統的磁盤的IO次數。

四,理解page和索引

MySQL內部,將來Buffer pool緩沖區中一定需要并且存在大量的page,所以MySQL必須將這些page管理起來。通過“先描述,再組織”。所以page內部并不是單純的存儲數據,page內部也需要寫入對應的管理信息。我們目前可以簡單的理解成一個個獨立的文件是由一個或者多個page構成的。

?思考一下:為何MySQL和磁盤進行IO交互時候,要采用page的方案進行交互呢?為什么不是用多少加載多少呢?

  • 因為預加載可以有效減少IO的次數。通過局部性原理,當前訪問某些數據或代碼的某一行時,下次訪問可能會在這次訪問的周邊進行訪問。
  • 往往IO效率低下的最主要矛盾不是單次IO數據量的大小,而是IO的次數。

?

不同的page,再MySQL中都是16KB,使用prev和next構成雙向鏈表。

  • ?上面的單個頁,在查詢數據的時候,直接將一整頁的數據加載到內存,以減少硬盤IO次數,從而提高性能。但是,我們也可以看到,現在的頁內部,實際上是采用了鏈表的結構,前一條數據指向后一條數據,本質上還是通過數據的逐條比較來取出特定的數據。
  • 如果有1千萬條數據,一定需要多個page頁保存起來,多個page彼此采用雙向鏈表連接起來,而每個page內部也是有 鏈表來管理的。那么查找特定的一條記錄,也一定是線性查找,效率太低了。

所以這時就需要引入目錄了。

頁目錄:

就以書籍為例,每本數都有目錄。我們如果要看指定的章節,找到章節有兩種做法:

  • 從頭逐頁的向后翻,直到找到目標內容。
  • 通過提供的目錄,找到指定的頁數。當然在找目錄的過程中,可以順序查找,不過因為目錄肯定少,所以可以快速提高定位。
  • 本質上,書本中的目錄是花了額外的紙做的,但卻提高了效率。
  • 所以,目錄是一種空間換時間的做法。

單頁情況:

針對之前鏈式結構的page頁,我們可以引入頁目錄。

那么當前,在一個page內部,引入了頁目錄。?比如,要查找id=4的記錄,之前線性遍歷4次,才能拿到結果。現在直接通過目錄2,直接定位新的其實位置,提高了效率。

多頁情況:

MySQL中每一頁的大小只有16KB,單個page大小固定,所以隨著數據量不斷增大,16KB不能存下所有數據,那么必定會有多個頁來存儲數據。

在單表數據不斷被插入 的情況下,MySQL會在容量不足的時候,自動開辟新的page來保存新的數據,然偶通過指針的方式馬,將所有page組織起來。

這樣我們就可以通過多個page的遍歷,page內部通過目錄快速定位數據。可是這樣,貌似也有效率問題,在page之間,還是線性遍歷,意味著還是需要大量的IO。將下一個page加載到內存,進行線性檢測。這樣就顯得我們 page內部的目錄有點杯水車薪了。

解決方案,給page也帶上目錄:

  • ?使用一個目錄項來指向某一頁,而這個目錄項不存放數據,只存放它指向page中最小數據的鍵值
  • 和頁內目錄不同,這種目錄管理的是頁,而頁內目錄管理的是數據。
  • 其中,每個目錄項的構成是鍵值+指針。

目錄頁(page目錄)管理一個個的目錄,目錄頁中的數據存放的就是指向那一頁中最小的數據。通過該數據,與我們要查找的數據進行比較,找到訪問哪個page。

對于一個page目錄,它的大小是16KB,假設忽略掉前后指針,該page只存儲一個數據和對應的指針,在64位環境下,16*1024/(4+8)=1365。即一個page目錄,大概可以管理1365個page。也就是1365*1024/1024/1024=21MB,大概可以管理21MB的數據。

但是,我們的page目錄也可能會產生線性遍歷造成的多次IO,降低效率問題。同樣,我們可以在上層再加一層目錄page。

一般而言,兩三層的設計已經足夠了 ,可以管理特別大的數據。

這個結構就是B+樹。

但是,實際存儲的時候,除了葉子節點之間還會以鏈表的形式連接,其他節點都不會連接。這剛好符合B+樹!

注意:

葉子節點保存有數據,其他節點不保存數據,只保存目錄項 。???

原因:非葉子節點不保存數據,那么就可以存儲更多的目錄項,目錄頁,就可以管理更多的page。換句話說,查找數據時,可以淘汰掉的目錄頁更多,進行 IO的次數就可以大大減少。在IO層面,提高了效率。同時,每一個page節點,都有目錄項,大大提高了搜索效率。


葉子節點為什么全部鏈接起來???

首先,這是B+樹的特點。所以MySQL使用這種數據結構。

方便進行范圍查找。

上面的圖,描述的就是MySQL innodb 下的索引結構。我們在建表的時候,就會生成這樣一顆B+樹,他會將我們表中的主鍵一列作為索引,而如果我們在建表的時候沒有指明主鍵,系統會默認生成一個主鍵。一般我們插入數據的時候,就是在該結構下進行CURD的。

總結:

  • page分為目錄頁和數據頁。目錄頁只存放各個下級page的最小鍵值。
  • 查找的時候,自頂向下,只需加載部分目錄頁到內存,即可完成查找過程,大大較少了IO次數。

?五,聚簇索引和非聚簇索引

前面所講到的都是innodb存儲引擎下的結構。

聚簇索引:innodb存儲引擎下的結構就是聚簇索引,在葉子節點中,索引page和數據page放在一起存儲。

非聚簇索引:MyISAM存儲引擎下的結構就是非聚簇索引,在葉子節點中,索引page和數據page分開存儲。也就是說葉子 節點沒有數據,只有對應數據的地址。

驗證:

mysql> create table test1(
? ? -> id int primary key,
? ? -> name varchar(20) not null)engine=innodb;

?mysql> create table test2( id int primary key, name varchar(20) not nuull)engine=MyISAM;

?當然,MySQL除了默認會建立主鍵索引外,我們用戶也有可能按照其他列信息建立索引,一般這種索引叫做普通索引。

  • 對于MyISAM而言,建立主鍵索引和普通索引沒有區別,主鍵索引的葉子節點存儲的是指向數據的指針,那么創建普通索引的時候,就是再創建一個B+樹,以指定列作為鍵值,葉子節點存儲指向數據的指針即可。所以,建立普通索引和主鍵索引沒有區別。
  • 而對于Innode而言,我們知道主鍵索引對應的B+樹,葉子節點會存放主鍵值和數據。在我們創建普通索引的時候,同樣會創建一顆B+樹,以指定列為鍵值,但是葉子節點中不存儲數據,而是存儲主鍵值。在查數據的時候,需要兩邊索引:首先通過普通索引(普通索引對應的B+樹)查找到主鍵值,然后通過主鍵值在主鍵索引(主鍵對應的B+樹)中查找數據。這種過程,叫做回表查詢

所以,建立索引本質就是以該列為鍵值,創建一顆B+樹。

六,索引操作

查詢索引

show keys from 表名;

show index from 表名;

創建主鍵索引

  • 第一種方式

-- 在創建表的時候,直接在字段名后指定 primary key
create table user1(id int primary key, name varchar ( 30 ));
  • 第二種方式?

-- 在創建表的最后,指定某列或某幾列為主鍵索引
create table user2(id int , name varchar ( 30 ), primary key(id));
  • 第三種方式?

create table user3(id int , name varchar ( 30 ));
-- 創建表以后再添加主鍵
alter table user3 add primary key(id);

主鍵索引的特點:

  • 創建主鍵索引的列,它的值不能為null,且不能重復
  • 主鍵索引的列基本上是int
  • 一個表中,最多有一個主鍵索引,當然可以使用復合主鍵
  • 主鍵索引的效率高(主鍵不可重復)

唯一索引的創建

  • 第一種方式

-- 在表定義時,在某列后直接指定 unique 唯一屬性。
create table user4(id int primary key, name varchar ( 30 ) unique);
  • 第二種方式

-- 創建表時,在表的后面指定某列或某幾列為 unique
create table user5(id int primary key, name varchar ( 30 ), unique(name));
  • 第三種方式?

create table user6(id int primary key, name varchar(30));

alter? table user6 add unique(name);

唯一索引的特點:?

  • 一個表中,可以有多個唯一索引
  • 查詢效率高
  • 如果在某一列建立唯一索引,必須保證這列不能有重復數據
  • 如果一個唯一索引上指定not null,等價于主鍵索引

案列:

?mysql> alter table test1 add unique(name);

普通索引的創建?

  • 第一種方式

create table user8(id int primary key,
name varchar ( 20 ),
email varchar ( 30 ),
index(name) --在表的定義最后,指定某列為索引);
  • 第二種方式?
create table user9(id int primary key, name varchar ( 20 ), email
varchar ( 30 ));
alter table user9 add index(name); -- 創建完表以后指定某列為普通索引
  • 第三種方式?

create table user10(id int primary key, name varchar ( 20 ), email
varchar ( 30 ));
-- 創建一個索引名為 idx_name 的索引
create index idx_name on user10(name);//給索引起名字idx_name

普通索引的特點:

  • ?一個表中可以有多個普通索引,普通索引在實際開發中用的比較多
  • 如果某列需要創建索引,但是該列有重復的值,那么我們就應該使用普通索引

全文索引的創建

當對文章字段或有大量文字的字段進行檢索時,會使用到全文索引。 MySQL 提供全文索引機制,但是有 要求,要求表的存儲引擎必須是MyISAM ,而且默認的全文索引支持英文,不支持中文

案列:

mysql> create table articles(
? ? -> id int unsigned auto_increment not null primary key,
? ? -> title varchar(200),
? ? -> body text,
? ? -> FULLTEXT(title,body))engine=myisam;

  • 查詢文章中有沒有database數據

如果使用如下查詢方式,雖然查詢出數據,但是沒有使用到全文索引:

mysql> select * from articles where body like '%database%';

可以使用 explain工具看一下,是否使用到索引

使用全文索引:

mysql> select * from articles where match(title,body) against ('database');

刪除索引

刪除主鍵索引

alter table? 表名 drop? primary key;

刪除其他索引

alter table 表名 drop index 索引名;

//索引名就是show keys from表名結果種的key_name字段

?drop index 索引名? on 表名;

索引創建原則?

  • 比較頻繁作為查詢條件的字段應該創建索引
  • 唯一性太差的字段不適合單獨創建索引,即使頻繁作為查詢條件
  • 更新非常頻繁的字段不適合作創建索引
  • 不會出現在where子句中的字段不該創建索引

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

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

相關文章

springboot項目啟動常見的問題以及配置以及一些使用技巧

1.配置倉庫 這里要把xml文件從國外的鏡像源改成國內的鏡像源。改鏡像源可以查看這篇文章 點擊查看 2.更改文件類型 方法一:右鍵文件找到Mark Dircetory as可以更改文件類型 方法二: 3.springboot本地Maven倉庫的位置 4.pom.xml文件報紅錯誤怎么辦 這…

【初探數據結構】二叉樹的順序結構——堆的實現詳解(上下調整算法的時間復雜度分析)

💬 歡迎討論:在閱讀過程中有任何疑問,歡迎在評論區留言,我們一起交流學習! 👍 點贊、收藏與分享:如果你覺得這篇文章對你有幫助,記得點贊、收藏,并分享給更多對數據結構感…

流量分析2

一,webshell流量 [GKCTF 2021]簽到 先看協議分級,大部分是tcp,里面有http的基于的行文本數據占了很大的比重,看看里面有什么 過濾http的流量 點擊一條流量,里面的內容進去后面有基于行的文本數據, 先解he…

頭歌實踐教學平臺--【數據庫概論】--SQL

一、表結構與完整性約束的修改(ALTER) 1.修改表名 USE TestDb1; alter table your_table rename TO my_table; 2.添加與刪除字段 #語句1:刪除表orderDetail中的列orderDate alter table orderDetail drop orderDate; #語句2:添加列unitPrice alter t…

在 React 中,組件之間傳遞變量的常見方法

目錄 1. **通過 Props 傳遞數據**2. **通過回調函數傳遞數據**3. **通過 Context API 傳遞數據**4. **通過 Redux 管理全局狀態**5. **通過事件總線(如 Node.js 的 EventEmitter)**6. **通過 Local Storage / Session Storage**7. **通過 URL 查詢參數傳…

Redis + 布隆過濾器解決緩存穿透問題

Redis 布隆過濾器解決緩存穿透問題 1. Redis 布隆過濾器解決緩存穿透問題 📌 什么是緩存穿透? 緩存穿透指的是查詢的數據既不在緩存,也不在數據庫,導致每次查詢都直接訪問數據庫,增加數據庫壓力。 例如&#xff1…

Vue動態添加或刪除DOM元素:購物車實例

Vue 指令系列文章: 《Vue插值:雙大括號標簽、v-text、v-html、v-bind 指令》 《Vue指令:v-cloak、v-once、v-pre 指令》 《Vue條件判斷:v-if、v-else、v-else-if、v-show 指令》 《Vue循環遍歷:v-for 指令》 《Vue事件處理:v-on 指令》 《Vue表單元素綁定:v-model 指令》…

vue h5實現車牌號輸入框

哈嘍,大家好,最近鵬仔開發的項目是學校校內車輛超速方面的統計檢測方面的系統,在開發過程中發現有個小功能,就是用戶移動端添加車牌號,剛開始想著就一個輸入框,提交時正則效驗一下格式就行,最后…

硬件基礎(5):(3)二極管的應用

文章目錄 [toc]1. **整流電路****功能**:**工作原理**:**應用實例**:電路組成:整流過程:電路的應用: 2. **穩壓電路****功能**:**工作原理**:**應用實例**:電路組成及功能…

Wireshark網絡抓包分析使用詳解

序言 之前學計網還有前幾天備考華為 ICT 網絡賽道時都有了解認識 Wireshark,但一直沒怎么專門去用過,也沒去系統學習過,就想趁著備考的網絡相關知識還沒忘光,先來系統學下整理點筆記~ 什么是抓包?抓包就是將網絡傳輸…

安心聯車輛管理平臺源碼價值分析

安心聯車輛管理平臺源碼的價值可從技術特性、功能覆蓋、市場適配性、擴展潛力及商業化支持等多個維度進行分析。以下結合實際應用進行詳細解讀: 一、技術架構與開發優勢 主流技術棧與高性能架構 源碼采用成熟的前后端分離架構,后端基于Java技術&#xff…

【操作系統】Docker如何使用-續

文章目錄 1、概述2、鞏固知識2.1、基礎命令2.2、容器管理2.3、鏡像管理2.4、網絡管理2.5、Compose 3、常用命令 1、概述 在使用Docker的過程中,掌握常用的命令是至關重要的。然而,隨著時間的推移,我們可能會遺忘一些關鍵的命令或對其用法變得…

ElementUI el-menu導航開啟vue-router模式

有沒有小伙伴遇到這么一種情況:ElementUI el-menu導航中,開啟vue-router 的模式后,點擊觸發事件而不進行路由跳轉? 別慌!下面直接說解決方案: 借助路由守衛進行判斷 給el-menu綁定切換事件,給…

【leetcode hot 100 17】電話號碼的字母組合

分析:當設計關鍵字“所有組合”時,要考慮深度優先遍歷、廣度優先遍歷(層次遍歷),其中: 深度優先搜索: 自頂向下的遞歸實現深搜定義子問題在當前遞歸層結合子問題結果解決原問題 廣度優先搜索 利…

Vue 2 探秘:visible 和 append-to-body 是誰的小秘密?

🚀 Vue 2 探秘:visible 和 append-to-body 是誰的小秘密?🤔 父組件:identify-list.vue子組件:fake-clue-list.vue 嘿,各位前端探險家!👋 今天我們要在 Vue 2 的代碼叢林…

C++學習之路:從頭搞懂配置VScode開發環境的邏輯與步驟

目錄 編輯器與IDE基于vscode的C開發環境配置1. 下載vscode、淺嘗編譯。番外篇 2. 安裝插件,賦能編程。3. 各種json文件的作用。c_cpp_properties.jsontask.jsonlaunch.json 總結&&彩蛋 編輯器與IDE 上一篇博客已經介紹過了C程序的一個編譯流程,從…

PPT 轉高精度圖片 API 接口

PPT 轉高精度圖片 API 接口 文件處理 / 圖片處理,將 PPT 文件轉換為圖片序列。 1. 產品功能 支持將 PPT 文件轉換為高質量圖片序列;支持 .ppt 和 .pptx 格式;保持原始 PPT 的布局和樣式;轉換后的圖片支持永久訪問;全…

VSCode 抽風之 兩個conda環境同時在被激活

出現了神奇的(toolsZCH)(base) 提示符,如下圖所示: 原因大概是:conda 環境的雙重激活:可能是 conda 環境沒有被正確清理或初始化,導致 base 和 toolsZCH 同時被激活。 解決辦法就是 :conda deactivate 兩次…

git | 回退版本 并保存當前修改到stash,在進行整合。[git checkout | git stash 等方法 ]

目錄 一些常見命令: git 回退版本 一、臨時回退(不會修改歷史,可隨時回到當前版本) 方法1:git checkout HEAD~1 問題:處于 detached HEAD 狀態下提交的,無法直接 git push ? 選項 1&…

如何使用 Postman 進行接口測試?

使用 Postman 這一工具,可以輕松地進行接口測試。以下是一份簡單的使用教程,幫助你快速上手。 Postman 接口測試教程:詳細步驟及操作技巧