mysql精講_Mysql 索引精講

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

format,png

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

索引種類(應用層面)

聚簇索引與非聚簇索引

覆蓋索引

最佳索引使用策略

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

首先不談Mysql怎么實現索引的,先馬后炮一下,如果讓我們來設計數據庫的索引,該怎么設計?

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

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

1.存儲的數據是非常非常多的

2.并且還不斷的動態變化

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

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

format,png

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

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

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

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

format,png

format,png

從上面圖可知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)的時候存儲引擎是怎么管理索引的呢?看下面的索引樹

format,png

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) 這種情況下他的索引樹是如下圖所示。

format,png

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

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

format,png

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

如果使用了聚簇索引(主鍵),則葉子節點上就包含行數據,可直接返回

如果使用了非聚簇索引(普通索引),則在葉子節點存了主鍵,再根據主鍵查詢一次上面 的聚簇索引,最后返回數據

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

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

1.2 Hash 索引(哈希表)

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

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

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

format,png

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

第一步,計算出hash值,hash(張三) = 1287

第二步,定位行號,比如key=1287 對應的行號為3

第三步,找到指定行并且比較name列值是否為張三做個校驗

format,png

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

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

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

索引列是 col2

format,png

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

假如有一條sql 語句?select * from test where col2=93;

上面這條語句會經歷兩次從索引樹查找過程

1.第一步從非聚簇索引的索引樹上找到包含col2=93的葉子節點,并定位到行的主鍵 3

2.第二步 根據主鍵 3 在從聚簇索引定位包含 主鍵=3的葉子節點并返回全部行數據。

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

format,png

結論:

聚簇索引:

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

非聚簇索引:

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

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兩個字段,所以使用了覆蓋索引。覆蓋索引有什么好處呢?先看一下下面這個圖

format,png

上面這個圖就是 聯合索引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值會導致索引無效

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

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

使用短索引

如果很長的字符串進行查詢,只需匹配一個前綴長度,這樣能夠節省大量索引空間

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

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

相關文章

pytorch lightning最簡上手

pytorch lightning最簡上手 pytorch lightning 是對原生 pytorch 的通用模型開發過程進行封裝的一個工具庫。本文不會介紹它的高級功能&#xff0c;而是通過幾個最簡單的例子來幫助讀者快速理解、上手基本的使用方式。在掌握基礎 API 和使用方式之后&#xff0c;讀者可自行到 …

RT-Smart 官方 ARM 32 平臺 musl gcc 工具鏈下載

前言 RT-Smart 的開發離不開 musl gcc 工具鏈&#xff0c;用于編譯 RT-Smart 內核與用戶態應用程序 RT-Smart musl gcc 工具鏈代碼當前未開源&#xff0c;但可以下載到 RT-Thread 官方編譯好的最新的 musl gcc 工具鏈 ARM 32位 平臺 比如 RT-Smart 最好用的 ARM32 位 qemu 平…

java list翻轉_JAVA實現兩種方法反轉單列表

/***authorluochengcheng* 定義一個單鏈表*/classNode {//變量private intrecord;//指向下一個對象privateNode nextNode;public Node(intrecord) {super();this.record record;}public intgetRecord() {returnrecord;}public void setRecord(intrecord) {this.record record;}…

OpenAI Whisper論文筆記

OpenAI Whisper論文筆記 OpenAI 收集了 68 萬小時的有標簽的語音數據&#xff0c;通過多任務、多語言的方式訓練了一個 seq2seq &#xff08;語音到文本&#xff09;的 Transformer 模型&#xff0c;自動語音識別&#xff08;ASR&#xff09;能力達到商用水準。本文為李沐老師…

mysql 工具 08s01_Mysql管理必備工具Maatkit詳解之十四(mk-kill)

mk-kill - 顧名思義&#xff0c;殺mysql線程。安裝方法查看這里。在一個OLTP的生產環境&#xff0c;一般不會讓sql執行過長的時間&#xff0c;特別是myisam這樣表鎖的引擎&#xff0c;如果出現長時間執行的sql一般是誤操作&#xff0c;要不就是出現問題了。出現這種情況&#x…

【經典簡讀】知識蒸餾(Knowledge Distillation) 經典之作

【經典簡讀】知識蒸餾(Knowledge Distillation) 經典之作 轉自&#xff1a;【經典簡讀】知識蒸餾(Knowledge Distillation) 經典之作 作者&#xff1a;潘小小 知識蒸餾是一種模型壓縮方法&#xff0c;是一種基于“教師-學生網絡思想”的訓練方法&#xff0c;由于其簡單&#xf…

深度學習三大謎團:集成、知識蒸餾和自蒸餾

深度學習三大謎團&#xff1a;集成、知識蒸餾和自蒸餾 轉自&#xff1a;https://mp.weixin.qq.com/s/DdgjJ-j6jHHleGtq8DlNSA 原文&#xff08;英&#xff09;&#xff1a;https://www.microsoft.com/en-us/research/blog/three-mysteries-in-deep-learning-ensemble-knowledge…

在墻上找垂直線_墻上如何快速找水平線

在裝修房子的時候&#xff0c;墻面的面積一般都很大&#xff0c;所以在施工的時候要找準水平線很重要&#xff0c;那么一般施工人員是如何在墻上快速找水平線的呢&#xff1f;今天小編就來告訴大家幾種找水平線的方法。一、如何快速找水平線1、用一根透明的軟管&#xff0c;長度…

百度地圖mysql打點_關于百度地圖連接MYSQL的問題,謝謝啦!

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓大家好&#xff0c;剛使用百度地圖API&#xff0c;請教大家一個問題&#xff0c;謝啦&#xff01;我需要從我的數據庫中取出字段為"city"的所有數據&#xff0c;然后通過bdGEO()函數在地圖上標注這些城市&#xff0c;我是…

PyTorch中的torch.nn.Parameter() 詳解

PyTorch中的torch.nn.Parameter() 詳解 今天來聊一下PyTorch中的torch.nn.Parameter()這個函數&#xff0c;筆者第一次見的時候也是大概能理解函數的用途&#xff0c;但是具體實現原理細節也是云里霧里&#xff0c;在參考了幾篇博文&#xff0c;做過幾個實驗之后算是清晰了&am…

Vision Transformer(ViT)PyTorch代碼全解析(附圖解)

Vision Transformer&#xff08;ViT&#xff09;PyTorch代碼全解析 最近CV領域的Vision Transformer將在NLP領域的Transormer結果借鑒過來&#xff0c;屠殺了各大CV榜單。本文將根據最原始的Vision Transformer論文&#xff0c;及其PyTorch實現&#xff0c;將整個ViT的代碼做一…

hdfs的副本數為啥增加了_HDFS詳解之塊大小和副本數

1.HDFSHDFS : 偽分布式(學習)NNDNSNNsbin/start-dfs.sh(開啟hdfs使用的腳本)bin/hdfs dfs -ls (輸入命令加前綴bin/hdfs dfs)2.block(塊)dfs.blocksize &#xff1a; 134217728(字節) / 128M 官網默認一個塊的大小128M*舉例理解塊1個文件 130M&#xff0c;默認一個塊的大小128M…

Linux下的ELF文件、鏈接、加載與庫(含大量圖文解析及例程)

Linux下的ELF文件、鏈接、加載與庫 鏈接是將將各種代碼和數據片段收集并組合為一個單一文件的過程&#xff0c;這個文件可以被加載到內存并執行。鏈接可以執行與編譯時&#xff0c;也就是在源代碼被翻譯成機器代碼時&#xff1b;也可以執行于加載時&#xff0c;也就是被加載器加…

mysql gender_Mysql第一彈

1、創建數據庫pythoncreate database python charsetutf8;2、設計班級表結構為id、name、isdelete&#xff0c;編寫創建表的語句create table classes(id int unsigned auto_increment primary key not null,name varchar(10),isdelete bit default 0);向班級表中插入數據pytho…

python virtualenv nginx_Ubuntu下搭建Nginx+supervisor+pypy+virtualenv

系統&#xff1a;Ubuntu 14.04 LTS搭建python的運行環境&#xff1a;NginxSupervisorPypyVirtualenv軟件說明&#xff1a;Nginx&#xff1a;通過upstream進行負載均衡Supervisor&#xff1a;管理python進程Pypy&#xff1a;用Python實現的Python解釋器PyPy is a fast, complian…

如何設置mysql表中文亂碼_php mysql表中文亂碼問題如何解決

為避免mysql中出現中文亂碼&#xff0c;建議在創建數據庫時指定編碼格式&#xff1a;復制代碼 代碼示例:create database zzjz CHARACTER SET gbk COLLATE gbk_chinese_ci;create table zz_employees (employeeid int unsigned not null auto_increment primary key,name varch…

java 按鈕 監聽_Button的四種監聽方式

Button按鈕設置點擊的四種監聽方式注&#xff1a;加粗放大的都是改變的代碼1.使用匿名內部類的形式進行設置使用匿名內部類的形式&#xff0c;直接將需要設置的onClickListener接口對象初始化&#xff0c;內部的onClick方法會在按鈕被點擊的時候執行第一個活動的java代碼&#…

java int轉bitmap_Java Base64位編碼與String字符串的相互轉換,Base64與Bitmap的相互轉換實例代碼...

首先是網上大神給的類package com.duanlian.daimengmusic.utils;public final class Base64Util {private static final int BASELENGTH 128;private static final int LOOKUPLENGTH 64;private static final int TWENTYFOURBITGROUP 24;private static final int EIGHTBIT …

linux查看java虛擬機內存_深入理解java虛擬機(linux與jvm內存關系)

本文轉載自美團技術團隊發表的同名文章https://tech.meituan.com/linux-jvm-memory.html一, linux與進程內存模型要理解jvm最重要的一點是要知道jvm只是linux的一個進程,把jvm的視野放大,就能很好的理解JVM細分的一些概念下圖給出了硬件系統進程三個層面內存之間的關系.從硬件上…

java 循環stringbuffer_java常用類-----StringBuilder和StringBuffer的用法

一、可變字符常用方法package cn.zxg.PackgeUse;/*** 測試StringBuilder,StringBuffer可變字符序列常用方法*/public class TestStringBuilder2 {public static void main(String[] args) {StringBuilder sbnew StringBuilder();for(int i0;i<26;i){char temp(char)(ai);sb.…