JAVA面試題之三—Mysql索引瞭解嘛?怎麼優化查詢效率?

Hash

只支持單條數據的查詢。很多時候我們需要更復雜的操作。

BTree

特點

  • 不再是二叉搜索,而是N叉搜索,樹的高度會降低,查詢快

  • 葉子節點,非葉子節點,都可以存儲數據,且可以存儲多個數據

  • 通過中序遍歷,可以訪問樹上所有節點

設計邏輯

  • 內存讀寫快,磁盤讀寫慢,而且慢很多

  • 磁盤預讀:

    磁盤讀寫並不是按需讀取,而是按頁預讀,一次會讀一頁的數據,每次加載一些看起來是冗餘的數據,如果未來要讀取的數據就在這一頁中,可以避免未來的磁盤讀寫,提高效率(通常,一頁數據是4K

  • 局部性原理:

    軟件設計要儘量遵循“數據讀取集中”與“使用到一個數據,大概率會使用其附近的數據”,這樣磁盤預讀能充分提高磁盤IO效能

B+TRee

現在mysql使用的是這種索引

改進點以及優勢

  • 仍然是N叉樹,層級小,非葉子節點不再存儲數據,數據只存儲在同一層的葉子節點上,B+樹從根到每一個節點的路徑長度一樣,而B樹不是這樣

  • 葉子之間,增加了鏈表(圖中紅色箭頭指向),獲取所有節點,不再需要中序遍歷,使用鏈表的next節點就可以快速訪問到

  • 範圍查找方面,當定位min與max之後,中間葉子節點,就是結果集,不用中序回溯(範圍查詢在SQL中用得很多,這是B+樹比B樹最大的優勢

  • 葉子節點存儲實際記錄行,記錄行相對比較緊密的存儲,適合大數據量磁盤存儲;

    非葉子節點存儲記錄的PK,用於查詢加速,適合內存存儲

  • 非葉子節點,不存儲實際記錄,而只存儲記錄的KEY的話,那麼在相同內存的情況下,B+樹能夠存儲更多索引

問題1:索引類型中normal、unique、Fulltext什麼意思?什麼區別?

normal:表示普通索引

unique:表示唯一的,不允許重複的索引,如果該字段信息保證不會重複例如身份證號用作索引時,可設置爲unique

full textl: 表示 全文搜索的索引。FULLTEXT 用於搜索很長一篇文章的時候,效果最好。用在比較短的文本,如果就一兩行字的,普通的 INDEX 也可以。

問題2:mysql5.7中使用的索引是 BTree?什麼時候開始用的B+Tree?什麼用Hash索引?

Hash索引

innoDB 引擎中不支持Hash索引。

hash索引一般用於內存數據庫,比如memory存儲引擎,數據放到內存裏,爲了加快速度,創建hash索引。

既然你提到InnoDB使用的B+ Tree的索引模型,那麼你知道爲什麼採用B+ 樹嗎?這和Hash索引比較起來有什麼優缺點嗎?

B+ Tree索引和Hash索引區別

  • 哈希索引適合等值查詢,但是無法進行範圍查詢

  • 哈希索引沒辦法利用索引完成排序

  • 哈希索引不支持多列聯合索引的最左匹配規則

  • 如果有大量重複鍵值得情況下,哈希索引的效率會很低,因爲存在哈希碰撞問題

聚簇索引、覆蓋索引

剛剛我們聊到B+ Tree ,那你知道B+ Tree的葉子節點都可以存哪些東西嗎?

InnoDB的B+ Tree可能存儲的是整行數據,也有可能是主鍵的值。

兩種情況:如果存儲了主鍵索引,就稱之爲聚簇索引;如果存儲了主鍵的值而不是主鍵索引,那就稱之爲非聚簇索引。

在 InnoDB 裏,索引B+ Tree的葉子節點存儲了整行數據的是主鍵索引,也被稱之爲聚簇索引。而索引B+ Tree的葉子節點存儲了主鍵的值的是非主鍵索引,也被稱之爲非聚簇索引。

聚簇索引查詢會更快?

因爲主鍵索引樹的葉子節點直接就是我們要查詢的整行數據了。而非主鍵索引的葉子節點是主鍵的值,查到主鍵的值以後,還需要再通過主鍵的值再進行一次查詢。

剛剛你提到主鍵索引查詢只會查一次,而非主鍵索引需要回表查詢多次。是所有情況都是這樣的嗎?非主鍵索引一定會查詢多次嗎?

(後來我才知道,原來這個過程叫做回表)

拿到索引之後,還需要到表根據索引查詢一次數據的過程,叫做回表。

覆蓋索引(covering index)指一個查詢語句的執行只用從索引中就能夠取得,不必從數據表中讀取。也可以稱之爲實現了索引覆蓋。

當一條查詢語句符合覆蓋索引條件時,MySQL只需要通過索引就可以返回查詢所需要的數據,這樣避免了查到索引後再返回表操作,減少I/O提高效率。

如,表covering_index_sample中有一個普通索引 idx_key1_key2(key1,key2)。當我們通過SQL語句:select key2 from covering_index_sample where key1 = ‘keytest’;的時候,就可以通過覆蓋索引查詢,無需回表

再舉個例子:

select id from table_name where name = ‘ZhangSan’.

這種情況下,可以根據 name 索引查詢 id,id就是要查詢的值,所以不用再查詢聚簇索引。直接就能查詢出結果。

聯合索引、最左前綴匹配

那你們在創建聯合索引的時候,需要做聯合索引多個字段之間順序你們是如何選擇的呢?

我們把識別度最高的字段放到最前面。

在創建多列索引時,我們根據業務需求,where子句中使用最頻繁的一列放在最左邊,因爲MySQL索引查詢會遵循最左前綴匹配的原則,即最左優先,在檢索數據時從聯合索引的最左邊開始匹配。

所以當我們創建一個聯合索引的時候,如(key1,key2,key3),相當於創建了(key1)、(key1,key2)和(key1,key2,key3)三個索引,這就是最左匹配原則。

舉個例子:加入建了一個聯合索引,使用 name 和 age 兩列。

1)where name = ?

2) where age = ?

3) where name = ? and age = ?

上面會用到索引的有哪些?

答:1)3)

索引下推、查詢優化

那你知道在MySQL 5.6中,對索引做了哪些優化嗎?

引入了 Index Condition Pushdown(索引下推) MySQL 5.6引入了索引下推優化,默認開啓,使用SET optimizer_switch = ‘index_condition_pushdown=off’; 可以將其關閉。官方文檔中給的例子和解釋如下:people表中(zipcode,lastname,firstname)構成一個索引

SELECT * FROM people WHERE zipcode=‘95054’ AND lastname LIKE ‘%etrunia%’ AND address LIKE ‘%Main Street%’;

如果沒有使用索引下推技術

則MySQL會通過zipcode=’95054’從存儲引擎中查詢對應的數據,返回到MySQL服務端,然後MySQL服務端基於lastname LIKE ‘%etrunia%’ 和 address LIKE ‘%Main Street%’ 來判斷數據是否符合條件。

如果使用了索引下推技術

則MYSQL首先會返回符合 zipcode=’95054’ 的索引,然後根據 lastname LIKE ‘%etrunia%’ 篩選出符合條件的索引後再返回到 MySQL 服務端,然後MySQL服務端基於address LIKE ‘%Main Street%’ 來判斷數據是否符合條件,這樣返回給MySQL服務端的索引數又會減少。有了索引下推優化,可以在有like條件查詢的情況下,減少回表次數。

你們創建的那麼多索引,到底有沒有生效,或者說你們的SQL語句有沒有使用索引查詢你們有統計過嗎?

可以通過explain查看sql語句的執行計劃,通過執行計劃來分析索引使用情況

那什麼情況下會發生明明創建了索引,但是執行的時候並沒有通過索引呢?

查詢優化器 一條SQL語句的查詢,可以有不同的執行方案,至於最終選擇哪種方案,需要通過優化器進行選擇,選擇執行成本最低的方案。

在一條單表查詢語句真正執行之前,MySQL的查詢優化器會找出執行該語句所有可能使用的方案,對比之後找出成本最低的方案。這個成本最低的方案就是所謂的執行計劃。

優化過程大致如下:

1、根據搜索條件,找出所有可能使用的索引

2、計算全表掃描的代價

3、計算使用不同索引執行查詢的代價

4、對比各種執行方案的代價,找出成本最低的那一個

參考:

1)https://mp.weixin.qq.com/s?__biz=MzIxMjE5MTE1Nw==&mid=2653202148&idx=1&sn=f7960b73fe099e43a1a291cf62f647ee&chksm=8c99d43ebbee5d28c1399c4ff9162833210ef91be225ae03222903eb4f9cba4f9e8f32c464b7&scene=126&sessionid=1585119435&key=e2ae4c71ebea12457e5f05275121dfa703190783fcc780e78f7a66df198eab57651067fd7a3f1f0c59d8fe2d32003926e2e4200a5b6f2d247915beea0052ced133ee08b1a7b1286502e97df048cc0094&ascene=1&uin=NDYyNzg4MDQw&devicetype=Windows+10&version=62080079&lang=zh_CN&exportkey=AYHkj3VEBOhhK%2B924HRFLME%3D&pass_ticket=x5DQeIsVVJRo3ezSGkXT75p%2FnCamSZ9%2BkMYoh68wbJbUYP2eXC2vE0J2xG6%2FNH9P

2)mysql索引:https://zhuanlan.zhihu.com/p/73204847

實戰:https://juejin.im/post/5decb37b6fb9a0161a0c267b

本文分享自微信公衆號 - 哥妞(gh_d18ec82f19ea)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

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