1. 程式人生 > >關於SQL優化這些你瞭解嗎?

關於SQL優化這些你瞭解嗎?

背景

  在當今這個網際網路的時代無非要解決兩大難題,其一是資訊保安,其二就是資料的儲存。而資訊保安則是在資料儲存的基礎之上。一個公司從剛開始成立到發展成一個有上百人甚至上千人團隊的時候,公司的業務量是呈上升趨勢,客戶及使用者也會越來越多;之前設計的表結構可能會顯得不合理,表與表之間的聯絡沒有一個穩定的業務功能劃分,從而表現出來的是相關表的備用欄位越來越不夠用甚至新加欄位,最壞的情況就是不同業務表之間會有資料冗雜。從而暴露出一些設計的問題,這也就是SQL優化點之一:資料庫表結構設計的合理性。近年來大資料越來越火,而大資料也是為了解決資料的儲存的手段之一,其目的是從海量的資料中收集到有價值的資訊然後儲存到資料庫中,因為資料量大傳統的資料庫無法儲存那麼多的資訊所以需要分析有價值的資訊後再做決定是否持久化。

優化點

  • 前提必備知識

  學會是用explain關鍵詞檢視SQL語句效能,explain好像是從MYSQL5.6.3開始支援 select、update、delete語句分析,之前只支援select語句。現在我們普遍都是用5.7,所以的話不需要太擔心。這裡的話不詳細講如何解讀explain輸出的效能資訊。請參看部落格文件:《MySQL優化之Explain命令解讀》

  • 優化之一 - 從資料庫設計方面考慮
  1. 表與表之間的業務聯絡要明確:表之間其實是有業務聯絡的,比如:class(primary key:class_id,所有班級資訊表)、student(primary key:student_num,所有學生資訊表)、student_class(primary key:stu_class_id,所有學生所在班級資訊表)著三張表,如果現在需要一張老師對應哪個班級的班主任的資訊表;那麼此時正確的方法是:新建 teacher、teacher_class表,而不是直接把老師的資訊插入到student表中然後用一個欄位來標識是老師還是學生。可能你看到這個你會想 ”我肯定會按正確的那種方式做啊“,但是這只是舉一個例子,其實在實際專案開發過程中表與表結構不會那麼單一,這個時候你就會犯錯誤而用欄位標識。但是也不能說是不能用欄位標識,這個要看欄位標識的兩種資訊對應的業務是否有交叉點來取捨。
  2. 表字段儘量使用數值型:因為數值型欄位在MySQL底層應用的時候相比string型別的話效能更好;具體為什麼效能更好就需要了解MySQL底層機制了,反正記住這點就好。
  3. 屬性儘量使用定長:以減少佔用儲存空間;如果你定義了一個 order_id varchar(32) ,當在儲存的時候有一條記錄的order_id=20180910242360,此時order_id實際佔用了14個位元組但是這個欄位的屬性長度是32,所以還有18個位元組長度是無用的但卻佔用著記憶體空間。
  4. 建立合理的索引:索引就是用某種資料結構來查詢對應的資訊,從而減低時間複雜度提高查詢效率。建立索引的前提也要明確,綜合考慮再打算是否需要建立索引,畢竟索引是需要佔用儲存空間的,有時候犧牲的空間卻換不回時間。
  • 優化之二 - 從SQL語句優化方面考慮
  1. 儘量將要輸出的欄位寫出來;不要使用 select * from where xxxxx ;這種形式的語句。我在這測試時是使用*代替,但是記住在生產環境上儘量將欄位替代*。
  2. 合理使用連表查詢;不僅是表的連線需要較大的記憶體消耗另外一方面如果表設計的不是很合理也會導致索引無效從而造成極壞的結果。
  3. 查詢的時候要注意是否走索引:假如你在name列建立了一個 name_index索引,查詢你使用 name Like'%xxxx' 或者 name Like'%xxxx%' 這種模糊查詢,那麼此時可能就不會走索引;你應該這樣  name Like'xxxx%' 。以下就是實際的一個例子:  

  建立索引:

-- 為cust_third_acct 建立一個普通索引alter table
cust_info
add index cust_third_acct_index(cust_third_acct);

  a:通過SQL查詢資訊: select * from sp_tunnel_user where cust_third_acct like'0200%';   以下就是滿足查詢條件的部分資訊

  b:分析Like'%xxxx%'的查詢效能: select * from sp_tunnel_user where cust_third_acct like'%0200%';  通過Explain效能分析命令可以知道:在這種查詢條件下並沒有執行索引,type=all表明該語句執行的時候進行的是全表掃描;雖然我們在cust_third_acct 這個欄位建立了索引,但是possible_keys=null則說明了 用 like'%0200%' 這種形式的條件是一定無法使用到 cust_third_acct_index 這個索引。(其他欄位的解析請參照《MySQL優化之Explain命令解讀》這篇文章,這裡不做過多的分析)。

  c:分析Like'xxxx%'的查詢效能: select * from sp_tunnel_user where cust_third_acct like'0200%';  與b查詢語句相比這個查詢的 possible_keys=cust_third_acct_index ,這說明這個語句可能會用到cust_third_acct_index這個索引,但是key=null表明在實際的執行過程中並沒有用到 cust_third_acct_index 索引;剛才我們也說了這種條件查詢只是可能會走索引但是不一定發生,這個跟MySQL的儲存引擎相關,但是我們使用的時候儘量以這種方式去查詢。

  

  4. 使用索引遵循最佳左字首特性,建立聯合索引的時候將常用的屬性放在左邊。比如:我們需在在一張表的 cust_id 和 cust_tp 建立一個聯合索引 cust_id_type,設定cust_id(不是唯一) 是比較常用的那麼我們就將cust_id放在左邊。

  建立聯合索引:

-- 為cust_id與cust_tp建立一個聯合索引alter table
cust_info
add index  cust_id_type(cust_id,cust_tp);

  5.使用符合索引的時候需要注意:使用聯合索引需要從左往右不間斷,索引才會生效,也就是說聯合索引使用的時候必須要連續但不要求全部使用。如:以上4我們建立了一個 cust_id_type 索引,當我們在使用的時候如果where條件中只使用了 cust_id,那麼也會走索引;如果where條件中只使用了 cust_tp,那麼這條語句不會走索引,以下就是一個例項:

  b:select * from sp_tunnel_user where cust_id='8888888888' and cust_tp='04'; 當查詢條件用到cust_id與cust_tp兩個欄位並且cust_id在前面的時候,就會用到聯合索引;通過 key=cust_id_type可以看到實際執行過程中是用到索引了的。

  c:select * from sp_tunnel_user where cust_id='8888888888' ; 當查詢條件只用到cust_id一個欄位時,也用到了聯合索引;通過 key=cust_id_type可以看到實際執行過程中是用到索引了的,這就是左字首原則。

  d:select * from sp_tunnel_user where cust_tp='04' ; 當查詢條件只用到cust_tp一個欄位時,但卻沒有用到索引;通過 key=null 可以看到實際執行過程並沒有用到索引,這也是左字首原則。

  • 優化之三 - 讀寫分離與分庫分表

  當資料量達到一定的數量之後,限制資料庫儲存效能的就不再是資料庫層面的優化就能夠解決的;這個時候往往採用的是讀寫分離與分庫分表同時也會結合快取一起使用,而這個時候資料庫層面的優化只是基礎。讀寫分離適用於較小一些的資料量;分表適用於中等資料量;而分庫與分表一般是結合著用,這就適用於大資料量的儲存了,這也是現在大型網際網路公司解決資料儲存的方法之一。至於怎麼讀寫分離、怎麼分表、怎麼分庫,這裡不做過多的闡述後續文章會有相關知識分享。