MySQL高級——索引 (內附索引高頻面試題)

目錄

 

一、索引介紹以及使用

1.1 什麼是索引?

1.2 索引的分類?

1.3 索引的創建、查詢、刪除 的方式?

 

二、高頻面試題(通過面試題更能瞭解索引)

2.1 什麼是索引?

2.2 MySQL索引是什麼樣的數據結構?

2.3 MySQL中的常用的存儲引擎 MyISAM與InnoDB的區別?

2.4 如何選擇存儲引擎 MyISAM與InnoDB?

2.5 MyISAM與InnoDB實現BTree索引的方式不同在哪?

2.6 爲什麼要使用索引?(索引的優點?)

2.7 索引是怎麼提高查詢速度的?

2.8 既然索引這麼多好處,爲什麼不給表中的每一列都創建索引?(索引的缺點?)

2.9 使用索引有哪些注意事項?(使用索引時,SQL語句怎麼優化?)

2.10 什麼是最左前綴原則?

2.11 什麼是覆蓋索引?


 

一、索引介紹以及使用

1.1 什麼是索引?

MySQL官方對索引的定義爲:索引(Index)是幫助MySQL高效獲取數據的數據結構。

從官方定義中,我們可以知道索引本質是一種數據結構。

詳細一點的解釋就是:
數據庫除了數據本身之外,數據庫還維護着一個滿足特定查找算法的數據結構,這些數據結構通過某種方式指向數據。如此一來,就可以在這些數據結構的基礎上實現高級查找算法,這種數據結構就是 索引。

簡單一點的解釋就是:
索引是排好序的可快速查找的數據結構。

形象一點的解釋就是:
索引就好像是新華字典的查找目錄,可以幫助你快速查找到字典中的指定內容。
索引也像是圖書館的書籍查找目錄,可以幫你快速查詢到你要的書在哪。

 

1.2 索引的分類?

  1. 單值索引:一個索引只包含一個列,一個表可以有多個單列索引。
  2. 複合索引:一個索引包含多個列。
  3. 唯一索引:索引列的值必須是唯一的,但允許有多個空值。

 

1.3 索引的創建、查詢、刪除 的方式?

索引的創建有兩種方法:CREATE 和 ALTER 。

/*ALTER*/
ALTER TABLE tableName ADD [UNIQUE] INDEX idx_name1 (column_name1);

 

/*CREATE*/
CREATE [UNIQUE] INDEX idx_name1 on tableName(colum_name1);

查詢索引:

/*查詢索引*/
SHOW INDEX FROM tableNmae

刪除索引:

/*刪除索引*/
DROP INDEX [indexName] ON tableName;

 

下面示範一下

用create創建索引:

 

用alter創建單值索引:

 

創建多值索引:

用alter創建多值索引也類似,這裏不演示了。

 

這裏順便說一下命名規範

非唯一索引的命名(單值或多值):idx_字段名   (多值:idx_字段名1_字段名2_字段名3.....)

唯一索引命名:uni_字段名

 

 

二、高頻面試題(通過面試題更能瞭解索引)

 

 

2.1 什麼是索引?

索引(Index)是幫助MySQL高效獲取數據的數據結構。
(具體的可看上面的索引介紹。)

 

 

2.2 MySQL索引是什麼樣的數據結構?

MySQL索引主要使用的兩種數據結構:

  1. 哈希索引
    哈希索引底層的數據結構就是哈希表,查詢很快。
    所以在數據庫的大部分需求爲單條記錄查詢的時候,可以選擇哈希索引。
    而其他大部分場景,一般選則BTree索引。
     
  2. BTree索引
    MySQL的BTree索引用的是BTree中的B+樹。
    不過對於不同的存儲引擎,實現的方式不同。
    比如主要的存儲引擎MyISAM和InnoDB中的實現方法就不同。
    (提到了存儲引擎MyISAM和InnoDB之後,可能會有下面三個“追命連擊”)

 

2.3 MySQL中的常用的存儲引擎 MyISAM與InnoDB的區別?

  1. InnoDB支持事務,而MyISAM不支持。
  2. InnoDB支持外鍵,而MyISAM不支持。
  3. InnoDB不支持全文索引,而MyISAM支持。
  4. InnoDB使用的是行級鎖,MyISAM使用的是表級鎖。
  5. InnoDB count(*) 時需要全表掃描,消耗資源多且速度慢;
    而MyISAM 是用一個變量保存了整個表的行數,count(*)時只需讀取該變量即可,消耗資源很少且速度很快。

 

 

2.4 如何選擇存儲引擎 MyISAM與InnoDB?

  1. InnoDB適合寫密集的的表,MyISAM適合讀密集的表。
  2. 數據庫做主從分離時,一般選擇MyISAM作爲主庫的存儲引擎,InnoDB作爲從庫的存儲引擎。
  3. 需要支持事務,且需要支持較高併發時,選擇InnoDB。
    不需要支持事務時,選擇MyISAM。

 

 

2.5 MyISAM與InnoDB實現BTree索引的方式不同在哪?

  1.  MyISAM: B+樹葉子節點的data域存放的是數據記錄的地址。在索引檢索的時候,首先按照B+樹搜索算法搜索索引,如果指定的Key存在,則取出其 data 域的值,然後以 data 域的值爲地址讀取相應的數據記錄。這被稱爲“非聚簇索引”。
     
  2. InnoDB: 其數據文件本身就是索引文件。相比MyISAM,索引文件和數據文件是分離的,其表數據文件本身就是按B+樹組織的一個索引結構,樹的葉子節點data域保存了完整的數據記錄。這個索引的key是數據表的主鍵,因此InnoDB表數據文件本身就是主索引。這被稱爲“聚簇索引(或聚集索引)”,而其餘的索引都作爲輔助索引,輔助索引的data域存儲相應記錄主鍵的值而不是地址,這也是和MyISAM不同的地方。在根據主索引搜索時,直接找到key所在的節點即可取出數據;在根據輔助索引查找時,則需要先取出主鍵的值,在走一遍主索引。 因此,在設計表的時候,不建議使用過長的字段作爲主鍵,也不建議使用非單調的字段作爲主鍵,這樣會造成主索引頻繁分裂。

 

 

2.6 爲什麼要使用索引?(索引的優點?)

  1. 可以大幅加快 數據的檢索速度(因爲大幅減少了檢索的數據量),  這也是創建索引的最主要的原因。
    (就像使用新華字典找一個字,如果沒有目錄,我們就需要一頁一頁的來查找;而如果有目錄,我們只需查詢一下目錄就可以快速找到。) 

  2. 通過索引列對數據進行排序,降低了數據排序的成本。使服務器避免了排序與創建臨時表。

  3. 通過創建唯一性索引,可以保證數據庫表中每一行數據的唯一性

  4. 將隨機IO變爲了順序IO

  5. 可以加速表和表之間的連接,在實現數據的參考完整性方面特別有意義。

 

 

2.7 索引是怎麼提高查詢速度的?

  1. 索引將無序的數據進行了排序,我們查詢時只需查詢索引即可快速查詢到所需數據(就像使用字典的目錄來查找)。

 

 

2.8 既然索引這麼多好處,爲什麼不給表中的每一列都創建索引?(索引的缺點?)

因爲索引也有一些缺點:

  1. 實際上索引也是一張表,該表保存了主鍵與索引,並指向實體表的記錄,所以索引也要佔用空間
  2. 索引雖然大幅提升了查詢速度,但是會降低更新表的速度。因爲在對錶中數據進行增刪改時,索引也要動態維護。這就會降低數據的維護速度(也就是降低更新表的速度)。
  3. 創建索引和維護索引也會耗費時間,並且數據量越大,耗費的時間越多。

 

 

2.9 使用索引有哪些注意事項?(使用索引時,SQL語句怎麼優化?)

  1. 要遵循最左前綴原則。
  2. 少在索引列上進行操作。
  3. 範圍條件之後的索引會失效。
  4. 使用模糊查詢時,%寫在最右邊,不然後面的索引會失效。
  5. 不等,空值,or ,這幾個會使索引失效,要少用。
  6. VARCHAR類型的數據,一定要記得寫引號,不然會使索引失效。
  7. 覆蓋索引查詢很快 ( 覆蓋索引不要寫 select * )。
  8. 單行訪問很慢。
    不要爲了從存儲中讀取一個數據塊而去獲取其中的一行。
    最好讀取的數據塊中包含儘可能多的所需要的行。

 

 

2.10 什麼是最左前綴原則?

使用多值索引時,要按索引字段的順序使用。

例如:
user表裏的屬性字段a、b、c 有一個多值索引 (a,b,c) idx_a_b_c 。

select * from user where a=1 and b=1 and c=1 ; //a,b,c可以使用索引
select * from user where a=1 ; // a可以使用索引
select * from user where a=1 and c=1; // a可以使用索引,c不能使用索引,因爲前面的b斷了。
select * from user where b=1 and c=1; // b,c 都不能使用索引,因爲前面的a斷了。

#注意
select * from user where c=1 and b=1 and a=1;
//這個a,c,c都能使用索引,因爲雖然順序不對,但是MySQL會幫我們調整順序。

 

 

2.11 什麼是覆蓋索引?

覆蓋索引,就是select的數據列只用從索引中就能夠取得,不必讀取數據行,MySQL可以利用索引返回select列表中的字段,而不用根據索引再去讀取數據文件。也就是說 查詢列要被所建立的索引覆蓋。

比如:user表有字段id、name、age、address,我們用字段name和age 建立索引 idx_name_age 。
那麼查詢時,
如果我們SQL是
select name,age from user  where username='猿兄' and age = 99; 
這就是覆蓋索引,要查的 name 和 age 都在索引裏,
所以我們根據索引查詢數據的時候,就可以直接從索引中獲得,而不用再去讀取數據庫。

而如果SQL是
select name,address from user  where username='猿兄' and age = 99; 
這樣的話,因爲address不在索引裏
當我們根據索引查詢數據時,還要再去讀取一下數據庫才能獲取address這個數據。
這樣就比較慢。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章