mysql 索引底層詳解

      網(wǎng)友投稿 818 2025-03-31

      mysql三層架構

      +--------------+ | 客戶端 | +--------------+ ↓ +--------------+ | 服務端 | +--------------+ ↓ +--------------+ | 存儲引擎 | +--------------+

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      mysql server層結(jié)構

      當客戶端需要查詢一條sql時,在server端內(nèi)部走了以下4步

      +--------------+ | 連接器 | +--------------+ ↓ +--------------+ | 分析器 | +--------------+ ↓ +--------------+ | 優(yōu)化器 | +--------------+ ↓ +--------------+ | 執(zhí)行器 | +--------------+

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      索引的作用

      加快數(shù)據(jù)的訪問

      將隨機io變成順序io

      大大減少了服務器需要掃描的數(shù)據(jù)量

      幫助服務器避免排序和臨時表

      減少io次數(shù),提高磁盤壽命

      索引缺點

      加了索引之后查詢會更快,但是當數(shù)據(jù)量大的時候,增刪改就會變慢;因為每次修改數(shù)據(jù)時除了數(shù)據(jù)本身,數(shù)據(jù)庫還需要維護索引的那顆B+樹;

      一張表最多能建多少個列和索引

      innoDB: 最多創(chuàng)建1017列, 最多64個二級索引,加上主鍵有65個, 單個索引最多包含16列, 索引最大長度767字節(jié)(其實行格式為REDUNDANT,COMPACT最高為767字節(jié),但行格式為DYNAMIC,COMPRESSED最高可達為3072字節(jié)), 行大小最大65536字節(jié)

      mysiam: 最多4096列, 最多64個二級索引, 單個索引最多包含16列, 索引最大長度1000字節(jié), 行大小最大65536字節(jié)

      一級索引和二級索引

      一級索引

      :索引和數(shù)據(jù)存儲在一起,都存儲在同一個B+tree中的葉子節(jié)點。一般主鍵索引都是一級索引。主鍵就是聚簇索引,一個表就一個主鍵,一個表也就一個聚簇索引,所以綜上所述,

      主鍵 = 一級索引 = 聚簇索引

      二級索引

      :二級索引樹的葉子節(jié)點存儲的是主鍵而不是數(shù)據(jù)。也就是說,在找到索引后,得到對應的主鍵,再回到一級索引中找主鍵對應的數(shù)據(jù)記錄。在innodb中,所有的二級索引B+樹都指向一級索引的key值,所以查詢二級索引時需要回表才能查到一整行數(shù)據(jù);

      索引是存儲在內(nèi)存還是磁盤的

      索引都是存儲在磁盤里面的,因為需要持久化存儲,內(nèi)存里也有,但都是每次查詢時從磁盤加載到內(nèi)存里的

      有或者無索引的情況下是怎么查找數(shù)據(jù)的?

      無索引:沒有索引的情況下,都會全表掃描,就是一條條地找,這無疑效率不高,又費io;

      有索引:有索引的情況下,會為這個索引生成一顆B+樹,有了這顆樹的幫助,查詢數(shù)據(jù)的效率會提升幾千倍;

      查詢比較慢,一般卡在哪?

      卡在io上,就是input和output,

      解決方案是提高io效率,

      減少io的次數(shù),

      減少io的量:盡可能地查詢減少查詢的數(shù)據(jù),盡量避免用select * from xxx

      去磁盤讀取數(shù)據(jù)的時候,是用多少讀取多少嗎?

      肯定不是啦,mysql和磁盤交互的時候是以頁為單位進行傳輸?shù)模J情況下,每頁大小為16K,,就像我們在電腦上新建一個txt文件,里面什么內(nèi)容都沒有,但它還是占用了4KB,mysql也一樣,有自己的最小頁大小,可通過 innodb_page_size 參數(shù)觀看數(shù)據(jù)頁大小

      mysql> show variables like 'innodb_page_size'; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | innodb_page_size | 16384 | +------------------+-------+

      1

      2

      3

      4

      5

      6

      很重要的概念:局部性原理

      數(shù)據(jù)和程序都有狙擊成群的傾向,同時之前被訪問過的數(shù)據(jù)很可能再次被查詢,空間局部性、時間局部性

      磁盤預讀

      mysql 索引底層詳解

      內(nèi)存跟磁盤交互時,一般情況下有一個最小的邏輯單元,稱之為頁(datapage),頁的大小由系統(tǒng)決定,一般是4k或8k,并且一定是整數(shù)倍的,4、8、16、32、64、128… 數(shù)據(jù)交互時,可以去頁的整數(shù)倍來進行讀取,innodb存儲引擎,每次讀取數(shù)據(jù)都是16k

      索引為什么能加快查詢

      要解決這個問題,我們就得先知道索引是怎么存儲的

      索引是怎么存儲的?

      一個索引對應一個B+樹,如果一張表建了10個索引,那就會有10個B+樹,

      OLAP聯(lián)機分析處理—數(shù)據(jù)倉庫–hive

      對海量歷史數(shù)據(jù)進行分析,產(chǎn)生決策性的影響

      OLTP聯(lián)機事務處理–關系型數(shù)據(jù)庫

      要求在很短的時效內(nèi)返回對用的數(shù)據(jù)

      為什么用B+樹來存儲索引?

      hash索引不適合用來做數(shù)據(jù)庫的結(jié)構,

      如果是單個等值值查詢(通過key查找value),那么就會非常快,

      不支持范圍查詢,進行范圍查詢時,必須要挨個遍歷

      對內(nèi)存的要求比較高,

      哈希沖突會造成數(shù)據(jù)散列不均勻,會產(chǎn)生大量的線性查詢,很浪費時間

      在mysql中有沒有hash索引

      答:有

      memory存儲引擎使用的是hash索引

      innodb支持自適應hash,就是由mysql來決定使用hash還是樹來存儲,人工無法干預

      存儲引擎的分類

      innodb :持久化 + 內(nèi)存

      memory :只存儲在內(nèi)存,不支持持久化,斷電就沒了,結(jié)構是hash表

      myisam :持久化

      可以在建表是自己指定存儲引擎,就像這樣

      create table (id bigint(20) primary key ,name varchar(10)) engine='innodb';

      1

      MySQL5.5版本之前,默認內(nèi)置存儲引擎是Myisam,

      MySQL5.5版本之后,MySQL的默認內(nèi)置存儲引擎已經(jīng)是InnoDB,

      樹的分類

      二叉樹

      BST樹(binary search tree)必須保證順序

      AVL樹 平衡二叉樹,有序

      紅黑樹

      B樹

      B+樹

      在很早很早很早很早以前,索引是用用二叉樹實現(xiàn)的,大概是2點幾版本的

      二叉樹本身是無序的,所以發(fā)展出了有序的BST樹,BST在插入數(shù)據(jù)的時候必須保證有序,左子樹必須小于根節(jié)點,右子樹必須大于根節(jié)點;

      bst樹插入時如果是連續(xù)遞增或遞減順序的話,就會退化成鏈表,所以衍生出了會旋轉(zhuǎn)的平衡二叉樹avl,

      avl樹插入慢,查詢快,因為插入的時候為了保證平衡,需要進行旋轉(zhuǎn)操作,平衡二叉樹有一個條件,為了保證平衡,最短子樹和最長子樹的長度差不能超過1,所以會經(jīng)常要旋轉(zhuǎn),旋轉(zhuǎn)也是需要性能開銷的。所以平衡二叉樹只能用于插入少、查詢多的數(shù)據(jù),當我們的查詢和插入一樣多 情況下,使用平衡二叉樹就不合適了,所以這時候又衍生出了一種新的數(shù)據(jù)結(jié)構:紅黑樹

      紅黑樹最長子樹只要不超過最短子樹的2倍即可,但是隨著數(shù)據(jù)的插入,發(fā)現(xiàn)樹的深度會變深,樹的深度越深,意味著io次數(shù)越多,就會影響數(shù)據(jù)讀取的效率;所以為了解決這個問題,就需要把有序的二叉樹,變成有序的多叉樹,這就是B樹

      B樹中每層都存儲數(shù)據(jù),但是每個磁盤塊能存儲的內(nèi)容是有限的,除了索引之外,還要存儲數(shù)據(jù),而數(shù)據(jù)占用的空間更多,這就使得能存儲的索引變少了,如果想要插入更多的數(shù)據(jù),就得在加一層,變成四層,但是這樣會增加io量,所以為了解決這個問題,衍生出了B+樹;

      B+樹只在葉子節(jié)點儲存數(shù)據(jù),非葉子層只存儲索引,并且B+樹不但可以從上往下查找,還可以從下往上查找數(shù)據(jù);

      聚簇索引和 非聚簇索引 的區(qū)別

      innodb只能有一個聚簇索引,但是有很多的非聚簇索引

      聚簇索引: 數(shù)據(jù)和索引是放在一起的,就是聚簇索引,就像這樣

      +----------+ | 索引值 | +----------+ | 數(shù)據(jù) | +----------+

      1

      2

      3

      4

      5

      非聚簇索引:數(shù)據(jù)和索引是分開存放的,在B+樹中索引值對應的是文件地址,就是非聚簇索引,可以肯定的是,所有的非聚簇索引都指向了聚簇索引,就像這樣

      +------------+ | 索引值 | +------------+ |數(shù)據(jù)文件地址| +------------+

      1

      2

      3

      4

      5

      innodb中,如果id是主鍵,后面我把name字段添加為索引,這棵樹是怎么樣存儲的?

      一開始我的主鍵是id字段,那么在B+樹中葉子節(jié)點的結(jié)構是這樣的

      +----------+ |主鍵索引值| +----------+ | 數(shù)據(jù) | +----------+

      1

      2

      3

      4

      5

      這時候我又把name字段設置為索引了,這時候mysql為這個name索引也創(chuàng)建一顆B+樹,這顆樹的葉子節(jié)點存的就不是數(shù)據(jù)了,如果存數(shù)據(jù)的話會造成冗余,所以這個name索引樹存的是主鍵id,就像這樣

      +----------+ | ye | +----------+ / \ +----------+ +----------+ | xin | | dong | +----------+ +----------+ | 主鍵id | | 主鍵id | +----------+ +----------+

      1

      2

      3

      4

      5

      6

      7

      8

      9

      innodb插入數(shù)據(jù)時必須要包含一個索引的key值

      向innodb插入數(shù)據(jù)的時候,必須要包含一個索引的key值,這個索引的key值,可以是主鍵,如果沒有主鍵,就是唯一鍵,如果沒有唯一鍵,那么就是一個自生成的6字節(jié)的rowid;

      myisam用的都是非聚簇索引;

      innodb只有一個聚簇索引,有多個非聚簇索引;

      什么是存儲引擎

      索引的創(chuàng)建跟存儲引擎是掛鉤的,存儲引擎表示不同的數(shù)據(jù)在磁盤存儲的文件格式也是不同的。

      mysql常用的存儲引擎有三個

      memory :內(nèi)存級別的存儲引擎,不支持持久化,斷電丟失數(shù)據(jù),hash索引

      myisam : mysql 5.5之前默認的存儲引擎,每次修改數(shù)據(jù)都會鎖表,不支持事務

      innodb : mysql 5.5之后默認的存儲引擎,支持事務、行鎖;

      mysql會自動創(chuàng)建索引嘛

      innodb只能有一個聚簇索引,但是有很多的非聚簇索引,向innodb插入數(shù)據(jù)的時候,必須要包含一個索引的key值,這個索引的key值,可以使主見,如果沒有主鍵,就是唯一鍵,如果沒有唯一鍵,那么就是一個自生成的6字節(jié)的rowid;

      為什么只能有一個聚簇索引

      因為主鍵只有一個,聚簇索引對應的就是主鍵字段,只有主鍵的索引B+樹才會存儲數(shù)據(jù),其他的二級索引存儲的都是主鍵的值;

      如果每個二級索引樹都存儲數(shù)據(jù)的話,就會造成數(shù)據(jù)的冗余;

      myisam和innodb區(qū)別

      myisam支持表鎖,innodb支持表鎖和行鎖

      myisam不支持外鍵,innodb支持外鍵

      myisam不支持事務,innodb支持事務

      在計算機內(nèi)存足夠的情況下,innodb效率比myisam高,因為innodb是優(yōu)先讀緩存, myisam是直接從磁盤讀取數(shù)據(jù)

      數(shù)據(jù)存儲在哪個目錄

      數(shù)據(jù)存儲在: 你的mysql目錄/data/db1/ 目錄下,

      其中,

      后綴為.opt的文件是一個配置文件,指定該數(shù)據(jù)庫的字符集編碼

      后綴為.frm的文件就是表結(jié)構

      后綴為.idb表示當前表用的存儲引擎是innodb

      后綴為.myd是數(shù)據(jù)文件。使用的存儲引擎是myisam

      后綴為.myi是索引文件,使用的存儲引擎是myisam

      索引監(jiān)控

      查詢語句為:show status like ‘Handler_read%’;

      結(jié)果說明:

      Handler_read_first 代表讀取索引頭的次數(shù),如果這個值很高,說明全索引掃描很多。

      Handler_read_key:代表一個索引被使用的次數(shù),如果我們新增加一個索引,然后通過這個索引來查詢數(shù)據(jù),,可以查看Handler_read_key是否有增加,如果有增加,說明sql用到索引。這個數(shù)量越大越好,大表示索引查詢使用的比較多;

      Handler_read_next:代表讀取索引的下列,按(主)鍵順序依次讀取之后的N行

      Handler_read_last : 從(主)鍵的最后位置開始讀取

      Handler_read_prev: 代表讀取索引的上列,一般發(fā)生在ORDER BY … DESC。

      Handler_read_rnd: 代表在固定位置讀取行,如果這個值很高,說明對大量結(jié)果集進行了排序、進行了全表掃描、關聯(lián)查詢沒有用到合適的KEY。

      Handler_read_rnd_next: 代表進行了很多表掃描,查詢性能低下。

      關于mysql 的mysql 回表、索引覆蓋、最左匹配、索引下推,請看我的另一篇文章 :添加鏈接描述

      MySQL 數(shù)據(jù)庫

      版權聲明:本文內(nèi)容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權內(nèi)容。

      版權聲明:本文內(nèi)容由網(wǎng)絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權內(nèi)容。

      上一篇:EXCEL2019怎么設置短日期
      下一篇:初學電子表格(初學電子表格制表)
      相關文章
      亚洲日本精品一区二区| 国产精品亚洲综合五月天| 亚洲色精品三区二区一区| 亚洲国产精品尤物yw在线| 亚洲一区二区三区日本久久九| 国产亚洲精品福利在线无卡一 | 国产精品亚洲二区在线| 亚洲人成影院在线高清| 久久久久亚洲av无码专区导航| 亚洲人成网站免费播放| 亚洲日韩中文字幕| 亚洲视频在线观看不卡| 亚洲精品乱码久久久久久蜜桃| yy6080亚洲一级理论| 狠狠色伊人亚洲综合成人| 久久亚洲精品中文字幕三区| 日本红怡院亚洲红怡院最新| 亚洲AV综合色一区二区三区| 久久亚洲国产精品| 亚洲小视频在线观看| 亚洲综合一区二区精品久久| 亚洲高清在线观看| 亚洲黄色片在线观看| 亚洲春黄在线观看| 亚洲人xxx日本人18| 亚洲一区二区三区在线观看网站| 亚洲国产精品自在拍在线播放| 国产亚洲高清不卡在线观看| 亚洲性猛交XXXX| 亚洲精品~无码抽插| 久久久青草青青亚洲国产免观| 亚洲色偷偷综合亚洲AVYP| 亚洲一区二区视频在线观看| 一本色道久久综合亚洲精品高清| 国产日产亚洲系列| 亚洲中文字幕第一页在线| 亚洲日本va中文字幕久久| 亚洲AV无码一区二区三区国产 | 无码专区—VA亚洲V天堂| 亚洲av永久无码精品漫画| 亚洲一区二区三区电影|