從零開始java數據庫SQL優化(一):一篇解決MYSQL查詢優化總綱

目錄

目錄

一:問題場景

二:優化

1.查詢計劃 

2.分析計劃

 連接類型

三:索引的使用與選擇

1.索引的使用以及優化

(1) MYSQL中的索引原理

(2) 4中樹結構在索引中的應用(附紅黑樹)

2、樹結構選擇合適的索引。

3、mysql中建立索引的規範

4、mysql的索引分類以及使用場景

(1)索引的總分類

(2)Mysql中的索引

 (3)、建立合適索引,避免濫用索引。

四:優化SQL減低查詢時間

1.使用limit關鍵字

2.添加合適的索引

3.避免全表查詢

五:SQL優化建議

1.SQL從程序中查詢到程序顯示結果的過程

2.SQL層級優化



一:問題場景

  在一次項目中,出現一個SQL優化問題,問題場景就是,在用戶登陸時,將用戶的部門、崗位、角色以及權限(其中權限整合在菜單表中,每2個表都是用一箇中間表關聯)查詢出來作爲一個全局常量(MSYQL數據庫)。

  不多說,直接上SQL語句吧。

SELECT 
			a.fk_user_id AS "fk_user_id",
			a.user_realname AS "user_realname",
			a.user_name AS "user_name",
			a.user_type AS "user_type",
			a.sex AS "sex",
			a.phone AS "phone",
			a.password AS "password",
			a.user_addr AS "user_addr",
			a.avater AS "avater",
			a.status AS "status",
			
			
			
			fr.role_id as role_id,
			fr.role_code as role_code,
			fr.role_name as role_name,
			fr.role_range as role_range,
			
			
			fd.dept_id as dept_id,
			fd.dept_name as dept_name,
			fd.parent_id     as dept_parent,
			fd.parent_ids     as dept_parents,
			fd.company_name as company_name, 
			 
			fp.post_id as post_id,
			fp.post_name as post_name,
			fp.post_split as post_split,
			
			m.perms as perms
			
			FROM fk_user a
		 	LEFT JOIN fk_user_role fkur ON fkur.user_id = a.fk_user_id
			LEFT JOIN fk_role fr ON fr.role_id = fkur.role_id
			LEFT JOIN fk_role_menu rm ON rm.role_id = fr.role_id
			LEFT JOIN fk_menu m ON m.menu_id = rm.menu_id
	
			LEFT JOIN fk_dept fd ON fd.dept_id = a.dept_id
			LEFT JOIN fk_user_post fup ON fup.user_id = a.fk_user_id
			LEFT JOIN fk_post fp ON fp.post_id = fup.post_id

 where a.user_name ='admin'  

  在使用本地數據庫連接(localhost:3306)基本查詢就消耗了0.270s左右。見下圖:

二:優化

1.查詢計劃 

   很尷尬,實際上查詢的幾張表數據一共也就在250條左右(其中菜單表和角色菜單表大概在160條),這裏我們再來看一下SQL的查詢計劃統計:

2.分析計劃

  其中,我們看type一行的查詢涉及到3個名詞:ALL,ref,eq_ref。Type學名爲連接類型,連接類型決定查詢時間。

 連接類型

  ALL:全表掃描,最耗時的查詢,即使在查詢出符合條件的數據,還要繼續查詢其餘剩下的數據。(在本例場景中實際代碼

              已經控制了用戶名唯一,那麼在查詢出該用戶就應該停止繼續往下查詢,但是如果要查詢所有的用戶則查詢類型肯定

              是ALL)。

INDEX: 加索引的全表查詢,比較耗時的一種查詢,就是在查詢字段上添加一個索引。衆所周知Mysql中的索引結構爲B+樹。在

              同等數據結構中,B+數據的時間複雜度爲  log(2)n優化程度僅次於1,降低了樹高(即查詢表列的行數減少了),常見

              的索引優化就是講表數據按照b+樹排列,較少全表查詢的實際行數。

RANGE:範圍搜索,可以看出在是將查詢數據行數按照一定的條件控制,減少實際查詢行數(一定是基於索引)。常見得IN,

             BETWEEN等都是這種類型。

REF:  單條件不限查詢。簡而言之,就是將查詢放在一定的範圍內查詢,允許重複查詢(這裏區別於全表在於使用的索引,雖然

          不是唯一索引)。

REF_EQ:單條件唯一查詢。與上面不同的是,我們知道查詢結果唯一,在查詢出結果就不在繼續查詢了,所以時間程度 <= REF

CONST: 主鍵條件查詢。將主鍵放在where條件之後,會別MYSQL優化器存儲爲一個常量。

三:索引的使用與選擇

1.索引的使用以及優化

  在上面分析可知,除了ALL沒有用到索引,其他所有的類型都用到了索引。那麼我們就先來看看mysql中的索引。

(1) MYSQL中的索引原理

  在Mysql5.7+,Mysql默認的存儲引擎爲InnoDB。該引擎有2中索引:B+樹索引以及哈希索引,其中哈希索引是Mysql更具表的使用情況自動創建的,無法人爲干涉。

(2) 4中樹結構在索引中的應用(附紅黑樹)

  在上面,我們說到InnoDB默認爲B+樹,其實在索引中同期的樹結構還有B樹,B-樹,B*樹,下面我們就談談幾種樹結構的特性。

 B樹:又稱 二叉樹結構。每一個節點擁有2個子節點,大於該節點走右節點,小於該節點做左邊。如圖所示:

                                                 

             通過圖形我們可以看出3層樹結構存儲7個數據(圖中爲了方便看,第三層省了一個)。查詢一次 最多走3層樹,效率明顯提高(可以看出其實存儲的是數  字的情況下比較好比較,這也是爲什麼我們有時候強調分 布式環境中最好不要使用UUID作爲主鍵的原因)。 b樹的時間複雜度 O(logN)

B-樹:多鏈路查找樹結構。每一個節點擁有>2個子節點。通過二分法查詢找到左右2個關鍵字然後去中間查詢。如圖

        

   如圖,如果我們需要查詢E這個節點。首先確定E在DG中,但是又不是D和G,因此我們取DG中間節點去查詢。在這裏我們看到3層樹結構存儲了至少17個關鍵字。但是吧,不一定說明其效率高於B樹,畢竟誰也說不清在去中間結構判斷消耗的時間。

B+樹:多鏈路近似二分法。B+樹在每一個連接節點不會存儲節點指針只存儲節點關鍵字,每一個非連接子節點存儲根節點和對應連接節點的數據。 B+樹的時間複雜度爲  log(M-1)N~log(M/2)N

         

  實際上,B+樹就是將對應鏈路數據下沉下沉到最後一層,鏈路上的其他只記錄關鍵字,不記錄對應的指針信息等。因此,在B+樹查詢中效率接近二分法而且比B+效率高。

B*樹: b+樹的變種,允許同級關鍵字可以向相鄰的兄弟節點上放。簡而言之,b+樹的每一個節點存放的關鍵字容量有限,點滿本節點就必須裂變出子節點。而B*樹,在本節點點滿後,可以問同層左右未滿的節點存放,充分利用了空間。(但是b*樹每一個節點的容量小於b+樹)

               

 毋庸置疑,B*樹查詢效率接近B+樹,但是在同級別上,其空間利用率很高。當然,如果B+樹在每一個節點存放數據相同,B+樹層級一定<=B*樹。

附:紅黑樹,

  紅黑樹也是一種多鏈路樹結構,每一條鏈路都是紅黑相間,根節點爲黑色。每一個子節點必然爲2個即使爲NULL也是需要該節點而且必爲黑色。

 

  紅黑樹的時間複雜度爲:O(lgn)。

 

2、樹結構選擇合適的索引。

  上面我們分析幾種樹結構,那麼分析完了有什麼作用呢?通過對應數據庫的樹結構,合理的設計表結構。比如Mysql的InnoDB的默認爲B+樹,那麼在設計表結構時就應該往這個方面靠。

3、mysql中建立索引的規範

  (1)命名規範:表名_字段名,需要加索引的字段,要在where條件中,數據量少的字段不需要加索引,如果where條件中是

                               OR關係,加索引不起作用,符合最左原則。

   (2)約束規範:索引中Index和key。其中Key是數據庫中的物理結構,即是約束,約束結構完整性,同時也是索引,包含外檢

                                  等。而Index則是數據庫的虛擬結構,只負責實現輔助查詢,他創建時會在表空間創建虛擬目錄以助輔助。

 

4、mysql的索引分類以及使用場景

  這裏,我們不談如何去創建索引,只談所有哪些?如何在合適的場景選擇合適的索引。

(1)索引的總分類

  索引分爲聚簇和非聚簇索引。

聚簇索引:按照表行物理排序爲順序的,其多行索引查詢的速度很快。(暫戲稱爲全文索引吧)

非聚簇索引:按照表字段順序爲順序的(也就是說這是針對單行數據),其單行查詢書讀很快。

 

(2)Mysql中的索引

普通索引:  沒有任何約束的索引,一般添加在常用的查詢字段上。比如我們在存儲文章到數據庫中,其中標題爲一個字段且這

                     個字段會被經常查詢,那麼就可以在該字段上添加一個索引。(當然這裏只是舉一個不合適的例子,一般針對文

                     章的存儲不會放入Mysql數據庫中,而是放入對應的搜索索引中的。)

 

唯一索引:  這個索引在普通索引上添加一個約束,當查詢到該條數據時,查詢就會停止然後返回結果。比如,在用戶表中查詢

                     用戶名就可以在該字段上添加一個唯一索引。畢竟多數的代碼設計都是保證了用戶名唯一,不唯一當我沒說。

 

全文索引:  在Mysql3.23+就支持了全文索引,當然這個索引目前只適用於Mysam並且在數據量特別大的情況下,生成全文索引

                    速度特別慢。

 

組合索引: 多個字段同時且多用查詢時,建立查詢。比如用戶表中的用戶名和密碼這倆個字段,在登錄時一定會誒查詢,那麼

                     我們針對username和pwd建立索引,最後生成username+pwd 和  pwd 2個索引,遵循最左原則。

 

 (3)、建立合適索引,避免濫用索引。

    在上面我們談到索引建立的好處,但是索引並不是越多越好,索引的亂建會導致Mysql服務性能下降嚴重時會導致服務崩潰。

原因在於一個索引字段在新增/修改/刪除,會在操作數據時 新增/修改/刪除 索引目錄。

 

四:優化SQL減低查詢時間

  在上面我們談到了除了ALL之外,所有的類型的查詢都用了索引,因此我們對索引進行講解。現在我們迴歸優化SQL降低查詢類型提高查詢效率。(這裏提供以下MYSQL的SQL語句性能分析文章)

1.使用limit關鍵字

   limit關鍵字在很大方面控制Send_data的時長。具體可看這篇從零開始java數據庫SQL優化(番外):SQL執行性能分析

 

2.添加合適的索引

  在對應的字段上添加合適的索引

3.避免全表查詢

  也就是避免Type = ALL

 

五:SQL優化建議

1.SQL從程序中查詢到程序顯示結果的過程

  (1)ORM框架解析參數,封裝成SQL語句

  (2)MYSQL接收到SQL語句,進行優化器編譯

 (3)執行SQL語句,將數據從I/O磁盤讀取到內存中

 (4)從帶村中讀取數據

 

2.SQL層級優化

  (1)ORM框架解析從參數,封裝SQL,這裏離說實話沒辦法,現在ORM開源框架如Mybatis等都已經封裝好

  (2)MYSQL-SERVER解析編譯。

           解析過程,通過解析SQL參數,封裝可查詢的語句。這裏其實對於一些where條件以及決定查詢Type都是這個過程決定的

                               因此,避免全表查詢的優化就在這一步。

          編譯過程,解析完成,開始對執行語句進行編譯。這裏可以優化,可以預編譯SQL語句,比如添加視圖,臨時表或者存儲過

                            程等讓其直接執行預編譯好的語句。

(3)I/O磁盤讀取到內存中,這裏優化就是索引級別的了,可以添加索引,即目錄索引配合SQL查詢

(4)內存讀取數據,這個沒辦法ORM框架已經封裝好,頂多網絡優化。

 

 

 

 

 

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