最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Mysql中的索引精講

 更新時間:2019年05月13日 11:07:34   作者:小小木  
這篇文章主要給大家介紹了關(guān)于Mysql中索引的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用Mysql具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

前言

開門見山,直接上圖,下面的思維導(dǎo)圖即是現(xiàn)在要講的內(nèi)容,可以先有個印象~


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

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

首先不談Mysql怎么實現(xiàn)索引的,先馬后炮一下,如果讓我們來設(shè)計數(shù)據(jù)庫的索引,該怎么設(shè)計?

我們首先思考一下索引到底想達到什么效果?其實就是想能夠?qū)崿F(xiàn)快速查找數(shù)據(jù)的策略,所以索引的實現(xiàn)本質(zhì)上就是一個查找算法。

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

1.存儲的數(shù)據(jù)是非常非常多的

2.并且還不斷的動態(tài)變化

所以實現(xiàn)索引時需要考慮到這兩個特點。我們需要找一個最合適的數(shù)據(jù)結(jié)構(gòu)算法來實現(xiàn)查找功能。

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

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

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

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

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

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

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


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

1.1 B-Tree 索引(B+樹)

先說明一下,雖然叫在Mysql官方叫做B-Tree索引,但采用的是B+樹數(shù)據(jù)結(jié)構(gòu)。

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

下面看下單列索引的數(shù)據(jù)怎么組織的。

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

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

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

2.葉子節(jié)點的值是有序的

3.葉子節(jié)點之間以鏈表形式關(guān)聯(lián)

下面在看一下多列(聯(lián)合)索引的數(shù)據(jù)怎么組織的。

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

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

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

如何通過B-tree快速查找數(shù)據(jù)?

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

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

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

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

1.2 Hash 索引(哈希表)

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

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

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

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

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

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

主鍵索引

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

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

唯一索引

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

唯一索引主要用于業(yè)務(wù)上的唯一約束,他跟主鍵索引的區(qū)別是,一個表可以有多個唯一索引

單列索引

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

以某一個字段為索引

聯(lián)合索引

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

兩個或兩個以上字段聯(lián)合組成一個索引。使用時需要注意滿足最左匹配原則!

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

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

什么是聚簇索引?

聚簇索引指的是他的 索引和行數(shù)據(jù) 在一起存儲。也就是在一顆B+樹的葉子結(jié)點上存儲的不僅是他的索引值,還有對應(yīng)的某一行的數(shù)據(jù)。待會兒看圖便知。

聚簇索引不是一種索引,而是一種數(shù)據(jù)存儲組織方式 ?。。?br />

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

如上所示,表test 由兩個索引,分別是主鍵 col1 和 普通索引 col2。那么這倆索引跟聚簇非聚簇有啥關(guān)系呢?

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

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

下面看下聚簇索引和非聚簇索引在索引樹上數(shù)據(jù)是怎么分布的,圖片摘自《高性能Nysql》

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

索引列是主鍵 col1

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

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

索引列是 col2

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

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

上面這條語句會經(jīng)歷兩次從索引樹查找過程

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

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

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

 結(jié)論:

  • 聚簇索引:

通常由主鍵或者非空唯一索引實現(xiàn)的,葉子節(jié)點存儲了一整行數(shù)據(jù)

  • 非聚簇索引:

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

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),且有個聯(lián)合索引 key(name,uid)那么

執(zhí)行如下面這條sql查詢時就用到了 覆蓋索引。

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

上面這條sql語句使用了聯(lián)合索引 key(name,uid),并且只需查找 name,uid兩個字段,所以使用了覆蓋索引。覆蓋索引有什么好處呢?先看一下下面這個圖

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

覆蓋索引好處

1.避免了對主鍵索引(聚簇)的二次查詢

2.由于不需要回表查詢(從表數(shù)據(jù)文件)所以大大提升了Mysql緩存的負載

總之大大提升了讀取數(shù)據(jù)的性能

5.最佳索引使用策略

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

獨立的列

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

select * FROM test where col1 + 1 =100; // 不能是表達式一部分
select * FROM test where ABS(col1) =100; // 不能是函數(shù)一部分

最左匹配原則

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

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

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

索引值不能是null值

單列索引有null值會導(dǎo)致索引無效

多列索引只要有個列有null值會導(dǎo)致索引無效

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

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

使用短索引

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

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。

相關(guān)文章

  • MySQL存儲引擎InnoDB架構(gòu)原理和執(zhí)行流程

    MySQL存儲引擎InnoDB架構(gòu)原理和執(zhí)行流程

    InnoDB是MySQL的當(dāng)前默認(rèn)存儲引擎,支持外鍵、行級鎖定和ACID事務(wù),通過BufferPool緩沖池緩存數(shù)據(jù),RedoLogBuffer和undo日志文件保證數(shù)據(jù)的持久性和回滾能力,MySQL宕機重啟時,InnoDB會根據(jù)LSN值決定是否需要從redo日志恢復(fù)數(shù)據(jù)
    2025-04-04
  • mysql如何修改表結(jié)構(gòu)(alter table),多列/多字段

    mysql如何修改表結(jié)構(gòu)(alter table),多列/多字段

    這篇文章主要介紹了mysql如何修改表結(jié)構(gòu)(alter table),多列/多字段問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • Mysql以utf8存儲gbk輸出的實現(xiàn)方法提供

    Mysql以utf8存儲gbk輸出的實現(xiàn)方法提供

    Mysql以utf8存儲gbk輸出的實現(xiàn)方法提供...
    2007-11-11
  • 一文深入探討MySQL是如何解決幻讀問題

    一文深入探討MySQL是如何解決幻讀問題

    SQL標(biāo)準(zhǔn)中定義了4種隔離級別,分別是讀未提交、讀已提交、可重復(fù)讀以及序列化。不同的隔離級別下,本文將重點探討下MySQL是如何解決幻讀問題的,需要的朋友可以跟著小編一起來探討一下
    2023-07-07
  • Mysqli基礎(chǔ)知識

    Mysqli基礎(chǔ)知識

    本文給大家講述的是Mysqli的基礎(chǔ)知識,非常的淺顯易懂,有需要的小伙伴就可以參考下。
    2015-07-07
  • Mysql索引的類型和優(yōu)缺點詳解

    Mysql索引的類型和優(yōu)缺點詳解

    這篇文章主要為大家詳細介紹了Mysql索引的類型和優(yōu)缺點,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • MySQL常用SQL語句總結(jié)包含復(fù)雜SQL查詢

    MySQL常用SQL語句總結(jié)包含復(fù)雜SQL查詢

    今天小編就為大家分享一篇關(guān)于MySQL常用SQL語句總結(jié)包含復(fù)雜SQL查詢,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-02-02
  • MySql報錯Table mysql.plugin doesn’t exist的解決方法

    MySql報錯Table mysql.plugin doesn’t exist的解決方法

    一般產(chǎn)生原因是手工更改my.ini的數(shù)據(jù)庫文件存放地址導(dǎo)致的,大家可以參考下下面的方法
    2013-02-02
  • Mysql復(fù)制表三種實現(xiàn)方法及grant解析

    Mysql復(fù)制表三種實現(xiàn)方法及grant解析

    這篇文章主要介紹了Mysql復(fù)制表三種實現(xiàn)方法及grant解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-09-09
  • 數(shù)據(jù)庫中間件MyCat的介紹

    數(shù)據(jù)庫中間件MyCat的介紹

    今天小編就為大家分享一篇關(guān)于數(shù)據(jù)庫中間件MyCat的介紹,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01

最新評論

崇阳县| 吉林市| 天门市| 临海市| 江孜县| 体育| 合阳县| 榆中县| 伊春市| 上思县| 武陟县| 纳雍县| 青龙| 睢宁县| 衡南县| 卓尼县| 河曲县| 虞城县| 盈江县| 中山市| 阳泉市| 江源县| 德安县| 郎溪县| 柘荣县| 常州市| 修文县| 文昌市| 西城区| 佛教| 陇西县| 林口县| 福海县| 宁明县| 佛冈县| 高陵县| 个旧市| 深水埗区| 张掖市| 古丈县| 闸北区|