面試官靈魂拷問:什麼是MySQL索引?爲何須要索引?

爲何須要學MySQL?

咱們天天都在訪問各類⽹站、APP,如微信、QQ、抖⾳、今⽇頭條、騰訊新聞等,這些 東西上⾯都存在⼤量的信息,這些信息都須要有地⽅存儲,存儲在哪呢?數據庫。mysql

因此若是咱們須要開發⼀個⽹站、app,數據庫咱們必須掌握的技術,常⽤的數據庫有 mysql、oracle、sqlserver、db2等。sql

上⾯介紹的⼏個數據庫,oracle性能排名第⼀,服務也是至關到位的,可是收費也是⾮常 ⾼的,⾦融公司對數據庫穩定性要求⽐較⾼,⼀般會選擇oracle。數據庫

mysql是免費的,其餘⼏個⽬前暫時收費的,mysql在互聯⽹公司使⽤率也是排名第⼀, 資料也⾮常完善,社區也⾮常活躍,因此咱們主要學習mysql。數組

篇幅所限,本文只詳寫了MySQL索引,須要的同窗可自行領取完整版MySQL學習筆記微信

1、什麼是索引?

索引就比如字典的目錄同樣 咱們一般都會先去目錄查找關鍵偏旁或者字母再去查找 要比直接翻查字典查詢要快不少數據結構

2、爲何要有索引?

然而咱們在使用mysql數據庫的時候也像字典同樣有索引的狀況下去查詢,確定速度要快不少架構

2.1問題:oracle

1.mysql數據存儲在什麼地方?

磁盤app

2.查詢數據慢,通常卡在哪?

IOide

3.去磁盤讀取數據,是用多少讀取多少嗎?

磁盤預讀

局部性原理:數據和程序都有彙集成羣的傾向,同時以前被訪問過的數據極可能再次被查詢,空間局部性,時間局部性

磁盤預讀:內存和磁盤發生數據交互的時候,通常狀況下有一個最小的邏輯單元,頁。 頁通常由操做系統以爲大小,4k或8k,而咱們在進行數據交互的時候,能夠取頁的整數倍來讀取。

關注公衆號:北遊學Java 便可獲取一份578頁PDF文檔的MySQL學習筆記

innodb存儲引擎每次讀取數據,讀取16k

4.索引存儲在哪?

磁盤,查詢數據的時候會優先將索引加載到內存中

5.索引在存儲的時候,須要什麼信息?須要存儲存儲什麼字段值?

key:實際數據行中存儲的值

文件地址

offset:偏移量

6.這種格式的數據要使用什麼樣的數據結構來進行存儲?

key-values

哈希表,樹(二叉樹、紅黑樹、AVL樹、B樹、B+樹)

7.mysql索引系統中不是按照剛剛說的格式存儲的,爲何?

OLAP:聯機分析處理----對海量歷史數據進行分析,產生決策性的策略----數據倉庫—Hive

OLTP:聯機事務處理----要求很短時效內返回對應的結果----數據庫—關係型數據庫(mysql、oracle)

3、mysql的索引數據結構

3.1哈希表:

HashMap數組加鏈表的結構,不適合做爲索引的緣由:

1.哈希衝突會形成數據散列不均勻,會產生大量的線性查詢,比較浪費時間

2.不支持範圍查詢,當進行範圍查詢的時候,必須挨個遍歷

3.對於內存空間的要求比較高

優勢: 若是是等值查詢,很是快

在mysql中有沒有hash索引?

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

2.innodb支持自適應hash

create table test(id int primary key,name varchar(30))
engine='innodb/memory/myisam'
-- 5.1以後默認innodb複製代碼

3.2樹:

樹這種數據結構有不少,咱們常見的有: 二叉樹、BST、AVL、紅黑樹、B樹、B+樹

①二叉樹:無序插入

這就是咱們的樹的結構圖,可是二叉樹的數據插入是無序的,也就是說當須要查找的時候,仍是得一個一個挨着去遍歷查找

②BST(二叉搜索樹): 插入的數據有序,左子樹必須小於根節點,右子樹必須大於根節點--------使用二分查找來提升效率

這樣的話若是要查詢數據,能夠經過二分查找,快速縮小範圍,減小了時間複雜度 **可是若是插入的順序是升序或者降序的話,樹的形狀會變成以下:

此時二叉搜索樹就會退化成鏈表,時間複雜度又會變成O(n)

③AVL:平衡二叉樹 爲了解決上述問題,經過左旋轉或右旋轉讓樹平衡 最短子樹跟最長子樹高度只差不能超過1

由圖咱們能夠看到,當順序插入的時候,會自動的進行旋轉,以達到平衡 可是會經過插入性能的損失來彌補查詢性能的提高 當咱們插入的數據不少時候,而查詢不多的時候,因爲插入數據會旋轉一樣會消耗不少時間

④紅黑樹(解決了讀寫請求同樣多) 一樣是通過左右旋讓樹平衡起來,還要變色的行爲 最長子樹只要不超過最短子樹的兩倍便可

查詢性能和插入性能近似取得平衡 可是隨着數據的插入、發現樹的深度會變深,樹的深度會愈來愈深,意味着IO次數越多,影響數據讀取的效率

⑤ B樹 爲了解決上述數據插入過多,樹深度變深的問題,咱們採用B樹 把原來的有序二叉樹變成有序多叉樹

舉例: 若是要查詢select * from table where id=14?

  1. 第一步,將磁盤一加載到內存中,發現14<16,尋找地址磁盤2
  2. 第二步,將磁盤二加載到內存中,發現14>11,尋找地址磁盤7
  3. 第三步,將磁盤七加載到內存中,發現14=14,讀取data,取出data,結束 思考:B樹就是完美的嘛?

問題1:  B樹不支持範圍查詢的快速查找,若是咱們查詢一個範圍的數據,查找到範圍一個邊界時,須要回到根節點從新遍歷查找,須要從根節點進行屢次遍歷,即使找到範圍的另外一個邊界,查詢效率會下降。問題2:  若是data存儲的是行記錄,行的大小隨着列數的增多,所佔空間會變大。這時,一個頁中可存儲的數據量就會變少,樹相應就會變高,磁盤IO次數就會變大。 思考2:三層B樹可以存儲多少條記錄?答: 假設一個data爲1k,innodb存儲引擎一次讀取數據爲16k,三層即161616=4096; 可是每每在開發中,一個表的數據要遠遠大於4096,難道要繼續加層,這樣豈不就加大了IO

4、爲何使用B+樹?

實際存儲表數據的時候,怎麼存儲呢? key 完整的數據行 改造B+樹

B+樹對B樹進行了改進,把數據全放在了葉子節點中,葉子節點之間使用雙向指針鏈接,最底層的葉子節點造成了一個雙向有序鏈表。例如:  查詢範圍 select * from table where id between 11 and 35?

  1. 第一步,將磁盤一加載到內存中,發現11<28,尋找地址磁盤2
  2. 第二步,將磁盤二加載到內存中,發現10>11>17,尋找地址磁盤5
  3. 第三步,將磁盤五加載到內存中,發現11=11,讀取data
  4. 第四步,繼續向右查詢,讀取磁盤5,發現35=35,讀取11-35之間數據,結束 因而可知,這樣的範圍查詢比B樹速度提升了很多

對比B樹和B+樹?

  • 葉子節點中才放數據

  • 非葉子節點中不存儲數據

  • B+樹每一個節點包含更多個節點,這樣作的好處,能夠下降樹的高度,同時將數據範圍變成多個區間,區間越多查詢越快

問題: 建立索引時用int仍是varchar?

答:視狀況而定,可是記住必定讓key越小越好

5、索引的建立

在建立索引以前,我先說一下存儲引擎 存儲引擎: 表示不一樣的數據在磁盤的不一樣表現形式 你們去觀察mysql的磁盤文件會發現 innodb: innodb的數據和索引都存儲在一個文件下.idb myisam: myisam的索引存儲在.MYI文件中,數據存儲在.MYD中

5.1聚簇索引和非聚簇索引

概念:判斷是不是聚簇索引就看數據和索引是否在一個文件中 innodb:

  1. 只能有一個聚簇索引,可是有不少非聚簇索引
  2. 向innodb插入數據的時候,必需要包含一個索引的key值
  3. 這個索引的key值,能夠是主鍵,若是沒有主鍵,那麼就是惟一鍵,若是沒有惟一鍵,那麼就是一個自生成的6字節的rowid

myisam: 非聚簇索引

MySQL—innodb----B+樹 索引和數據存儲在一塊兒,找到索引便可讀取對應的數據

MySQL—myisam----B+樹 索引和存儲數據的地址在一塊兒,找到索引獲得地址值,再經過地址找到對應的數據

5.2回表

接下來,我會建立一張案例表給你們展現

CREATE TABLE user_test(
id INT PRIMARY KEY AUTO_INCREMENT,-- id爲主鍵
uname VARCHAR(20) ,
age INT,
gender VARCHAR(10),
 KEY `idx_uname` (`uname`) -- 索引選擇爲名字
)ENGINE = INNODB;

INSERT INTO user_test VALUES(1,'張三',18,'男');
INSERT INTO user_test VALUES(NULL,'馬冬梅',19,'女');
INSERT INTO user_test VALUES(NULL,'趙四',18,'男');
INSERT INTO user_test VALUES(NULL,'王老七',22,'男');
INSERT INTO user_test VALUES(NULL,'劉燕',16,'女');
INSERT INTO user_test VALUES(NULL,'萬寶',26,'男');複製代碼
select * from user_test where uname = '張三';
-- 當咱們表中有主鍵索引的時候,咱們再去設置一個uname爲索引,那麼此時這條sql語句的查詢過程應該以下:複製代碼

首先先根據uname查詢到id,再根據id查詢到行的信息 這樣的操做走了兩棵B+樹,就是回表 當根據普通索引查詢到聚簇索引的key值以後,再根據key值在聚簇索引中獲取數據 咱們能夠發現這樣的操做是很浪費時間的,所以咱們平常操做的時候,儘可能減小回表的次數

5.3覆蓋索引

select id,uname from table where uname = '張三';
-- 根據uname 能夠直接查詢到id,uname兩個列的值,直接返回便可
-- 不須要從聚簇索引查詢任何數據,此時叫作索引覆蓋複製代碼

5.4最左匹配

在說最左匹配以前,咱們先聊一下幾個名詞 主鍵(通常爲一個列)-------->聯合主鍵(多個列) 索引-------->聯合索引(可能包含多個索引列)

-- 假設有一張表,有id,name,age,gender四個字段,id是主鍵,name,age是組合索引列
-- 組合索引使用的時候必須先匹配name,而後匹配age

select * from table where name = ? and age = ? ;-- 生效
select * from table where name = ?;-- 生效
select * from table where age = ? ;-- 不生效
select * from table where age = ? and name = ? ;-- 生效

--在mysql內部有優化器會調整對應的順序複製代碼

5.5索引下推

mysql5.7以後,默認支持的一個特色 舉一個例子:

select * from table where name = ? and age = ? ;
-- mysql裏的三層架構:
-- 客戶端:JDBC
-- 服務端:server
-- 存儲引擎:數據存儲
在沒有索引下推以前,根據name從存儲引擎中獲取符合規則的數據,在server層對age進行過濾
有索引下推以後,根據name、age兩個條件從存儲引擎中獲取對應的數據複製代碼

分析:有索引下推的好處,若是咱們有50條數據,咱們經過過濾會獲得10條數據,若是沒有索引下推,會先獲取50條再去排除獲得10條,而有了下推以後,咱們會直接在存儲引擎就過濾成了10條

相關文章
相關標籤/搜索