面試題整理-MYSQL索引


一、什么是索引  

  - 官方定義: 一種幫助mysql提高查詢效率的數據結構
  - 索引的優點:
    大大加快數據查詢速度
  - 索引的缺點:
    1)維護索引需要耗費數據庫資源
    2)索引需要占用磁盤空間
    3——當對表的數據進行增刪改的時候,因為要維護索引,速度會受到影響

二、索引分類  

  - a.主鍵索引
    設定為主鍵后數據庫會自動建立索引,innodb為聚簇索引

  - b.單值索引
    即一個索引只包含單個列,一個表可以有多個單列索引

  - c.唯一索引
    索引列的值必須唯一,但允許有空值

  - d.復合索引
    即一個索引包含多個列

  - e.Full Text 全文索引 (My5.7版本之前 只能由於MYISAM引擎)
    全文索引類型為FULLTEXT,在定義索引的列上支持值的全文查找,允許在這些索引列中插入重復值和空值。全文索引可以在CHAR、VARCHAR、TEXT類型列上創建。MYSQL只有MYISAM存儲引擎支持全文索引

三、索引的基本操作

1.主鍵索引 自動創建
--建表 主鍵自動創建主鍵索引
create table t_user(id varchar(20) primary key,name varchar(20));
--查看索引
show index from t_user;

2.單列索引(普通索引|單值索引)
--建表時創建
create table t_user(id varchar(20) primary key, name varchar(20),key(name));  
'注意:隨表一起建立的索引名同列名一致'
      
--建表后創建
create index nameindex on t_user(name);

--刪除索引
drop index 索引名 on 表名

3.唯一索引
--建表時創建
 create table t_user(id varchar(20) primary key,name varchar(20),unique(name));
 
--建表后創建
create unique index nameindex on t_user(name);

4.復合索引
---建表時創建
 create table t_user(id varchar(20) primary key,name varchar(20),age int,key(name,age));
 
--建表后創建
 create index nameageindex on t_user(name,age);

四、索引底層原理

1.思考
---建表
create table t_emp(id int primary key,name varchar(20),age int);

--插入數據
insert into t_emp values(5,'d',22);
insert into t_emp values(6,'d',22);
insert into t_emp values(7,'e',21);
insert into t_emp values(1,'a',23);
insert into t_emp values(2,'b',26);
insert into t_emp values(3,'c',27);
insert into t_emp values(4,'a',32);
insert into t_emp values(8,'f',53);
insert into t_emp values(9,'v',13);

--查詢
select * from t_emp;

 

 

 思考:為什么上面數據明明沒有按順序插入,為什么查詢時卻是有順序呢?

  - 原因是: mysql底層為主鍵自動創建索引,創建索引會進行排序;
  - 也就是 mysql 底層真正存儲是這樣的;
  - 為什么要排序呢?因為排序之后在查詢就相對比較快了,如查詢 id=3 的我只需要按照順序找到 3 就行啦(如果沒有排序大海撈針,全靠運氣)

 

 

 回答:為了進一步提高效率mysql索引又進行了優化

  - 就是基於頁的形式進行管理索引;
  - 如查詢 id=4 的直接先比較頁先去頁目錄中找,再去數據目錄中找。

 

 

 索引原理:上面這種索引結構稱之為 B+ 樹數據結構,那么什么是 B+ 樹呢?

  - 參考資料: https://www.cnblogs.com/lianzhilei/p/11250589.html

B+Tree 是在 B-Tree 基礎上的一種優化,使其更適合實現外存儲索引結構,InnoDB 存儲引擎就是用 B+Tree 實現其索引結構;

從上一節中的 B-Tree 結構圖中可以看到每個節點中不僅包含數據的 key 值,還有 data 值。而每一個頁的存儲空間是有限的,如果data數據較大時將會導致每個節點(即一個頁)能存儲的 key的數量很小,當存儲的數據量很大時同樣會導致 B-Tree 的深度較大,增大查詢時的磁盤 I/O 次數,進而影響查詢效率。在 B+Tree 中,所有數據記錄節點都是按照鍵值大小順序存放在同一層的葉子節點上,而非葉子節點上只存儲 key 值信息,這樣可以大大加大每個節點存儲的 key 值數量,降低 B+Tree 的高度;

B+Tree 相對於 B-Tree 有幾點不同:

  1. 非葉子節點只存儲鍵值信息;

  2. 所有葉子節點之間都有一個鏈指針;

  3. 數據記錄都存放在葉子節點中。

  • InnoDB 存儲引擎中頁的大小為 16KB,一般表的主鍵類型為 INT(占用 4 個字節)或 BIGINT(占用 8 個字節),指針類型也一般為 4 或 8 個字節,也就是說一個頁( B+Tree 中的一個節點)中大概存儲 16KB / ( 8B + 8B ) = 1K 個鍵值(因為是估值,為方便計算,這里的K取值為〖10〗^3)。也就是說一個深度為 3 的 B+Tree 索引可以維護 10^3 * 10^3 * 10^3 = 10 億 條記錄;

  • 實際情況中每個節點可能不能填充滿,因此在數據庫中,B+Tree的高度一般都在2~4層。mysql的InnoDB存儲引擎在設計時是將根節點常駐內存的,也就是說查找某一鍵值的行記錄時最多只需要1~3次磁盤I/O操作。

五、聚簇索引和非聚簇索引

  - 聚簇索引: 將數據存儲與索引放到了一塊,索引結構的葉子節點保存了行數據;
  - 非聚簇索引:將數據與索引分開存儲,索引結構的葉子節點指向了數據對應的位置。

注意:在 Innodb 中,在聚簇索引之上創建的索引稱之為輔助索引,非聚簇索引都是輔助索引,像復合索引、前綴索引、唯一索引。輔助索引葉子節點存儲的不再是行的物理位置,而是主鍵值,輔助索引訪問數據總是需要二次查找

                  

 

 

 

 

1)InnoDB 存儲引擎

 

  • InnoDB 使用的是聚簇索引,將主鍵組織到一棵 B+ 樹中,而行數據就儲存在葉子節點上,若使用 "where id = 14" 這樣的條件查找主鍵,則按照 B+ 樹的檢索算法即可查找到對應的葉節點,之后獲得行數據;

  • 若對 name 列進行條件搜索,則需要兩個步驟:第一步在輔助索引 B+ 樹中檢索 name,到達其葉子節點獲取對應的主鍵。第二步使用主鍵在主索引 B+ 樹種再執行一次 B+ 樹檢索操作,最終到達葉子節點即可獲取整行數據。(重點在於通過其他鍵需要建立輔助索引)

  • 聚簇索引默認是主鍵,如果表中沒有定義主鍵,InnoDB 會選擇一個唯一且非空的索引代替。如果沒有這樣的索引,InnoDB 會隱式定義一個主鍵(類似oracle中的RowId)來作為聚簇索引。如果已經設置了主鍵為聚簇索引又希望再單獨設置聚簇索引,必須先刪除主鍵,然后添加我們想要的聚簇索引,最后恢復設置主鍵即可。

2)MYISAM 存儲引擎

 

  • MyISAM使用的是非聚簇索引,非聚簇索引的兩棵B+樹看上去沒什么不同,節點的結構完全一致只是存儲的內容不同而已,主鍵索引B+樹的節點存儲了主鍵,輔助鍵索引B+樹存儲了輔助鍵。表數據存儲在獨立的地方,這兩顆B+樹的葉子節點都使用一個地址指向真正的表數據,對於表數據來說,這兩個鍵沒有任何差別。由於索引樹是獨立的,通過輔助鍵檢索無需訪問主鍵的索引樹

          

 

注意點1:使用聚簇索引的優勢
  - 問題: 每次使用輔助索引檢索都要經過兩次B+樹查找,看上去聚簇索引的效率明顯要低於非聚簇索引,這不是多此一舉嗎?聚簇索引的優勢在哪?

  - 由於行數據和聚簇索引的葉子節點存儲在一起,同一頁中會有多條行數據,訪問同一數據頁不同行記錄時,已經把頁加載到了Buffer中(緩存器),再次訪問時,會在內存中完成訪問,不必訪問磁盤。這樣主鍵和行數據是一起被載入內存的,找到葉子節點就可以立刻將行數據返回了,如果按照主鍵Id來組織數據,獲得數據更快;

  - 輔助索引的葉子節點,存儲主鍵值,而不是數據的存放地址。好處是當行數據放生變化時,索引樹的節點也需要分裂變化;或者是我們需要查找的數據,在上一次IO讀寫的緩存中沒有,需要發生一次新的IO操作時,可以避免對輔助索引的維護工作,只需要維護聚簇索引樹就好了。另一個好處是,因為輔助索引存放的是主鍵值,減少了輔助索引占用的存儲空間大小。

注意點2:聚簇索引需要注意什么?

  - 當使用主鍵為聚簇索引時,主鍵最好不要使用uuid,因為uuid的值太過離散,不適合排序且可能出現新增加記錄的uuid,會插入在索引樹中間的位置,導致索引樹調整復雜度變大,消耗更多的時間和資源;
  - 建議使用int類型的自增,方便排序並且默認會在索引樹的末尾增加主鍵值,對索引樹的結構影響最小。而且主鍵值占用的存儲空間越大,輔助索引中保存的主鍵值也會跟着變大,占用存儲空間,也會影響到IO操作讀取到的數據量。

注意點3:為什么主鍵通常建議使用自增 id
  - 聚簇索引數據的物理存放順序與索引順序是一致的,即:只要索引是相鄰的,那么對應的數據一定也是相鄰地存放在磁盤上的。如果主鍵不是自增id,那么可以想象,它會干些什么,不斷地調整數據的物理地址、分頁,當然也有其他一些措施來減少這些操作,但卻無法徹底避免。但如果是自增的,那就簡單了,它只需要一頁一頁地寫,索引結構相對緊湊,磁盤碎片少,效率也高。

注意點4:什么情況下無法利用索引呢?
  - 查詢語句中使用LIKE關鍵字
    在查詢語句中使用 LIKE 關鍵字進行查詢時,如果匹配字符串的第一個字符為“%”,索引不會被使用。如果“%”不是在第一個位置,索引就會被使用;

  - 查詢語句中使用多列索引
    多列索引是在表的多個字段上創建一個索引,只有查詢條件中使用了這些字段中的第一個字段,索引才會被使用;

  - 查詢語句中使用OR關鍵字
    查詢語句只有OR關鍵字時,如果OR前后的兩個條件的列都是索引,那么查詢中將使用索引。如果OR前后有一個條件的列不是索引,那么查詢中將不使用索引。

每天進步一點點,就自信一點點 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM