MySQL——索引優化分析

爲什麼你寫的sql查詢慢?爲什麼你建的索引常失效?通過本章內容,你將學會MySQL性能下降的原因,索引的簡介,索引創建的原則,explain命令的使用,以及explain輸出字段的意義。助你瞭解索引,分析索引,使用索引,從而寫出更高性能的sql語句。加油!!!!


在這裏插入圖片描述

1:SQL性能下降的原因

主要原因:
1:查詢語句寫的爛
2:索引失效
3:關聯查詢太多join ( 設計缺陷或不得已的需求)
4:服務器調優及各個參數設置(緩衝、線程數等)

2:常見通用的Join查詢

2.1 SQL執行順序

首先我們寫一條查詢語句

SELECT DISTINCT
    < select_ list >
FROM 
     <left_ table> < join _type >
JOIN < right_ table> ON < Joln_condition >
 WHERE
     < where condition >
GROUE BY
      <group by list >
HAVING
     < having _ condition >
ORDER BY
      <order by condition >
  LIMIT <limit number>

mysql讀這條語句是按如下順序執行的
在這裏插入圖片描述
如下是SQL執行順序圖解
在這裏插入圖片描述

2.2 七種JOIN理論

在這裏插入圖片描述
MySQL 的七種 join用法

3:索引簡介

  • MySQL官方對索引的定義爲:索引(Index) 是幫助MySQL高效獲取數據的數據結構。可以得到索引的本質:索引是數據結構。(素引的目的在於提高查詢效率,可以類比字典,如果要查“mysql"這個單詞,我們肯定需要定位到m字母,然後從下往下找到y字母,再找到剩下的sql。如果沒有索引,那麼你可能高要從a–Z開始找。如果我想找到Java開頭的單詞呢?或者Oracle開頭的單詞呢?
  • 你可以簡單理解爲"排好序的快速查找數據結構”(在數據之外,數據庫系統還維護着滿足特定查找算法的數據結構,這些數據結構以某種方式(引用)數據,這樣就可以在這些數據結構上實現高級查找算法,這種數據結構,就是索引,如下圖)
    在這裏插入圖片描述

爲了加快Col2的查找,可以維護一個右邊所示的二又查找樹,每個節點分別包含索引鍵值和-一個指向對應數據記錄物理地址的指針,這樣就可以運用二叉者找在一 定的復朵度內獲取到相應數據,從而快速的檢索出符合條件的記錄。

  • 一般來說索引本身也很大,不可能全部存儲在內存中,因此索引往往以索引文件的形式存儲的磁盤上
  • 我們平常所說的索引,如果沒有特別指明,都是指B樹(多路搜索樹,並不一定是二叉的)結構組織的索引複合索引,前綴索引,唯一索引默認都是使用B+樹索引,統稱索引。當然,除了B+樹這種類型的索5index)等。

3.1 索引優劣勢

優勢:

  • 類似大學圖書館建書日索引,提高數據檢索的效率,降低數據庫的I0成本
  • 通過索引列對數據進行排序,降低數據排序的成本,降低了CPU的消耗

劣勢:

  • 實際上索引也是一張表,該表保存了主鍵與索引字段。並指向實體表的記錄,所以索引列也是佔用空間的
  • 雖然索引大大提高了查詢速度,有時卻會降低更新表的速度,如對錶進行INSERT, UPDATE 和DELETE. 因爲更新表時,MySQL不僅要保存數據,還要保存一下索引文件每次更新添加了索引列的字段,都會調整因爲更新所帶來的鍵值變化後的索引信息
  • 索引只是提高效率的一個因素,如果你的MySQL有大數據量的表,就需費花時間研究建立最優秀的素引,或優化查訊

3.2 索引分類和建索引命令語句

索引分類:

  • 單值索引:即一個索引只包含單個列,一個表可以有多個單列索引
  • 唯一索引:索引列的值必須唯一,但允許有空值
  • 複合索引:即一個索引包含多個列

建索引命令語句

# 創建:
CREATE [UNIQUE ] INDEX indexName ON mytable(columnname(length)); 
ALTER mytable ADD [UNIQUE ] INDEX [indexName] ON (columnname(length))
# 刪除:
DROP INDEX [indexName] ON mytable;
# 查看:
SHOW INDEX FROM table_ name/G

#   使用ALTER命令(四種方式來添加數據表索引)
#  1:該語句添加一個主鍵,意味着索引值必須是唯一的,且不可以爲null
ALTER TABLE b ,name ADD PRIMARY KLY (column list);
# 2:這條語句創建索引的值必須是唯一的(除了null外,null可呢會出現很多次)
 ALTER TABLE tb name ADD UNKQUL index_name ;
# 3:添加普通索引,索引值可呢出現很多次
 ALIER TABLE tb_name ADO INDEX index name (clumnm _list);
 # 4:該語句指定了索引爲FULLTEXT,用於全文索引
 АLТЕR ТАВLЕ tb_nаmе АDО FULLТЕХІ іndе. nаmе (соumm_list);

3.3 索引結構和原理

BTree索引
在這裏插入圖片描述

  • [初始化介紹]
    一顆b+樹,淺藍色的塊我們稱之爲一個磁盤塊,可以看到每個磁盤塊包含幾個數據項(深藍色所示)和指針(黃色所示),如磁盤塊1包含數據項17和35.包含指針P1、P2、P3,P1表示小於17的磁盤塊,P2表示在17和35之間的磁盤塊,P3表示大於35的磁盤塊。真實的數器存在於葉子節點即3、5、9、10、13、15、28、29、36、60、75、79、90、99。非葉子節點只不存儲真實的數據,只存儲指引搜素方向的數據項,如17. 35並不真實存在於數據表中。
  • [查找過程]
    如果要查找數據項29,那麼首先會把磁盤塊1由磁盤加載到內存,此時發生一次I0,在內存中用二分查找確定29在17和35之間,鎖定磁盤換1的P2指針,內存時間因爲非常短(相比磁盤的IO)可以忽略不計,通過磁盤塊1的P2指針的磁盤地址把磁盤塊3由磁盤加載到內存,發生第二次I0,29在26和30之間,鎖定磁盤塊3的P2指針,通過指針加載磁盤塊8到內存,發生第三次I0,同時內存中做二分查找找到29,結束查詢,總計三次IO.

真實的情況是,3層的b+樹可以表示上百萬的效據,如果上百萬的數據查我只需要三選I0,性能提高將是巨大的,如果沒有索到增每個數據項都要發生一次IO,那麼總共需要百萬次的IO,顯然成本非常非常高。

3.4 是否要建索引的情況

以下情況要建索引

  1.主鍵自動建立唯一索引
  2.頻繁作爲查詢條件的字段應該創建索引
  3.查詢中與其它表關聯的字段,外鍵關係建立索引
  4.頻繁更新的字段不適合創建索引,因爲每次更新不單單是更新了記錄還會更新索引
  5.Where條件裏用不到的字段不創建索引
  6.單鍵/組合索引的選擇問題,who? (在高併發下傾向創建組合索引)
  7.查詢中排序的字段,排序字段若通過索引去訪問將大大提高排序速度
  8.查詢中統計或者分組字段

以下情況不要建索引

 1.表記錄太少
 2.經常增刪改的表
 3.數據重複且分佈平均的表字段,因此應該只爲最經常查詢和最經常排序的數據列建立索引.
 注意,如果某個數據列包含許多重複的內容,爲它建立索引就沒有太大的實際效果。
 (    假如一個表有10萬行記錄, 有一個字段A只有T和F兩種值,且每個值的分佈概率大約爲50%,那麼對這種表A字段建索引一.般不會提高數據庫的查詢速度。
 索引的選擇性是指索引列中不同值的數目與表中記錄數的比。
 如果一個表中有2000條記錄,表索引列有1980個寧不同的值,那麼這個索引的選擇性就是1980/2000=0. 99。  一個索引的選擇性越接近於1,這個索引的效率就越高。
)

4:性能分析

4.1 MySql Query Optimizer

在這裏插入圖片描述
1 :Mysq|中 有專門負責優化SELECT語 句的優化器模塊(Optimizer),主要功能:通過計算分析系統中收集到的統計信息,爲客戶端請求的Query提供他認爲最優的執行計劃(他認爲最優的數據檢索方式,但不見得是DBA認爲是最優的,這部分最耗費時間)
2:當客戶端向MySQL請求一條Query,命令解析器模塊完成請求分類,區別出是SELECT並轉發給MySQLQuery Optimizer時,MySQL Query Optimizer首先會對整條Query進行優化,處理掉一些常 量表達式的預算,直接換算成常量值。並對Query中的查詢條件進行簡化和轉換,如去掉一些無用或顯而易見的條件、結構調整等。 然後分析Query中的Hint信息(如果有),看顯示Hint信息是否可以完全確定該Query的執行計劃。如果沒有Hint或Hint信息還不足以完全確定執行計劃,則會讀取所涉及對象的統計信息,根據Query進行寫相應的計算分析,然後再得出最後的執行計劃。

4.2 MySQL常見瓶頸

CPU:CPU在飽和的時候一般發生在數據裝入內存或從磁盤上讀取數據時候
IO:磁盤I/O瓶頸發生在裝入數據遠大於內存容量的時候
服務器硬件的性能瓶頸:top,free, iostat和vmstat來查看系統的性能狀態

4.3 explain使用簡介

  • 使用EXPLAIN關鍵字可以模擬優化器執行SQL查詢語句,從而知道MySQL是|如何處理你的SQL語句的。分析你的查詢語句或是表結構的性能瓶頸

4.3.1 explain可以幹嘛

1:表的讀取順序
2:數據讀取操作的操作類型
3:哪些索引可以使用
4:哪些索引被實際使用
5:表之間的引用
6:每張表有多少行被優化器查詢

4.3.2 explain怎麼玩

explain+SQL語句

例如:
在這裏插入圖片描述

4.3.2.1 id介紹

  • select查詢的序列號id,包含一組數字, 表示查詢中執行select子句或操作表的順序
  • id的三種情況

id相同,執行順序由上至下
id不同,如果是子查詢,id的序號會遞增,id值越大優先級越高,越先被執行
id相同不同,同時存在

舉例:在數據庫中創建三張表
在這裏插入圖片描述用explain+SQL語句查看id的三種情況
在這裏插入圖片描述
這裏需要重點了解的是type爲ALL,全表掃描的性能是最差的,假設數據庫中有幾百萬條數據,在沒有索引的幫助下會異常卡頓。
在這裏插入圖片描述
這裏需要重點了解的是type爲ALL,全表掃描的性能是最差的,假設數據庫中有幾百萬條數據,在沒有索引的幫助下會異常卡頓。
在這裏插入圖片描述
這裏需要重點了解的是type爲ALL,全表掃描的性能是最差的,假設數據庫中有幾百萬條數據,在沒有索引的幫助下會異常卡頓。

4.3.2.2 select_type

在這裏插入圖片描述

  1. SIMPLE :簡單的select查詢,查詢中不包含子查詢或者UNION
  2. PRIMARY :查詢中若包含任何複雜的子部分,最外層查詢則被標記爲
  3. SUBQUERY:在SELECT或WHERE列表中包含了子查詢
  4. DERIVED: 在FROM列表中包含的子查詢被標記爲DERIVED (衍生),MySQL 會遞歸執行這些子查詢,把結果放在臨時表裏。
  5. 若第二個SELECT出現在UNION之後,則被標記爲UNION。若UNION包含在FROM子句的子查詢中,外層SELECT將被標記爲: DERIVED
    6:UNION RESULT :從UNION表獲取結果的SELECT

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

4.3.2.3 type

  • type顯示查詢使用了何種類型。(較爲重要的一個指標)
  • 從最好到最差依次是:

System>const>eq_ref>ref>range>index>ALL

一般來說,得保證查詢至少達到range級別,最好可以達到ref

1:system:表只有一行記錄(等於系統表),這是const類型的特列,平時不會出現,這個也可以忽略不計
2:const: 表示通過索引一次就找到了,const用於比較primary key或者unique索引。因爲只匹配一行數據, 所以很快。
如將主鍵置於where列表中, MySQL就能將該查詢轉換爲一個常量
3:eq_ref :唯一性索引掃描,對於每個索引鍵,表中只有一 條記錄與之匹配。常見於主鍵或唯一 索引掃描
4:ref: 非唯一性索引掃描,返回匹配某個單獨值的所有行。
 本質上也是一種索引訪問,它返回所有匹配某個單獨值的行,然而,      
 它可能會找到多個符合條件的行,所以他應該屬於查找和掃描的混合體
5:range:只檢索給定範圍的行,使用一個索引來選擇行。key 列顯示使用了哪個索引。
一般就是在你的where語句中出現了between、<、>、in等的查詢      
這種範圍掃描索引掃描比全表掃描要好,因爲它只需要開始於索引的某一點,而結束語另一點,不用掃描全部索引。
6:index:FullIndexScan,index與ALL區別爲index類型只遍歷索引樹。這通常比ALL快,
因爲索引文件通常比數據文件小。(也就是 說雖然All和Index都是讀全表,但index是 從索引中讀取的,而all是從硬盤中讀的)
7:ref: Full Table Scan, 將遍歷全表以找到匹配的行
8:all:(full table scan)全表掃描無疑是最差,若是百萬千萬級數據量,全表掃描會非常慢。

一般來說,得保證查詢至少達到range級別,最好能達到ref.
簡單地說是const是直接按主鍵或唯一鍵讀取,eq_ref用於聯表查詢的情況,按聯表的主鍵或唯一鍵聯合查詢。

在這裏插入圖片描述

4.3.2.3 possible_keys和key

1:possible_ keys :顯示可 能應用在這張表中的索引,一個或多個。
查詢涉及到的字段 上若存在索引,則該索引將被列出,但不一定 被查詢實際使用
2:key:實際使用的索引。如果爲NULL,則沒有使用索引。查詢中若使用了覆蓋索引,則該索引僅出現在key列表中

在這裏插入圖片描述

4.3.2.3 key_len

  • 表示索引中使用的字節數,可通過該列計算查詢中使用的索引的長度。在不損失精確性的情況下,長度越短越好。key_ len顯示的值爲索引字段的最大可能長度,並非實際使用長度,即key_ len是 根據表定義計算而得,不是通過表內檢索出的
    在這裏插入圖片描述

4.3.2.4 ref

  • 顯示索引的那一列被使用了,如果可以的話,是一個常數(const),那些列或常量被用於查找索引列上的值

4.3.2.5 rows

  • 根據表統計及索引選用情況,大致估算出找到所需的記錄所需要讀取的行數

在這裏插入圖片描述
在這裏插入圖片描述

4.3.2.5 Extra

  • 包含不適合在其他列中顯示,但又十分重要的信息
  1. Using filesort:說明mysql會對數據使用一個外部的索引排序,而不是按照表內的索引順序進行讀取。MySQL中無法利用索引完成的排序操作稱爲“文件排序”
    在這裏插入圖片描述
  2. Using temporary:使了用臨時表保存中間結果,MySQL在對查詢結果排序時使用臨時表。常見於排序order by和分組查詢grqup by。
    在這裏插入圖片描述
  3. Using index:表示相應的select操作中使用了覆蓋索引(Covering Index), 避免訪問了表的數據行,效率不錯!
    如果同時出現using where,表明索引被用來執行索引鍵值的查找;
    如果沒有同時出現using where,表明索引用來讀取數據而非執行查找動作。
    覆蓋索引含義:就是select的數據列只用從索引中就能夠取得,不必讀取數據行,MySQL可以利用索引返回select列表中的字段,而不必根據索引再次讀取數據文件,換句話說查詢列要被所建的索引覆蓋。

如果要使用覆蓋索引,一定要注意select列表中只取出需要的列,不可seleat *,因爲如果將所有字段一起做索引會導致索引文件過大,查詢性能下降。

5:索引優化案例和索引失效情況

這一章小編寫不來,就看看別人的例子把,加油,自己亂寫的在這
索引失效的10種情況

可以參考索引優化中的例子,特別好
參考文章索引失效的七種情況

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