1. 程式人生 > >MYSQL的優化總結

MYSQL的優化總結

結合《高效能Mysql》和某公司的Mysql高效能優化範例,以及自己在工作中總結的一些SQL語句優化知識,在此給大家分享下希望對大家有用。

.設計資料庫首先需要注意的就是資料型別的選取

1.選擇優化的資料型別需要遵循的原則

1.資料型別更小的更好

2.簡單就好

3.儘量避免NULL

2.如果儲存的字串長度幾乎相等,使用CHAR 定長字串型別。

3.合適的字元儲存長度,不但節約資料庫表空間、節約索引儲存,更重要的是提升檢索速度

         4.DATETIMETIMESTAMP列都可以儲存相同型別的資料:時間和日期,精確到秒,但是TIMESTAMP只使用DATETIME一半的儲存空間,但是

TIMESTAMP允許的時間範圍小。datetime型別取值範圍:1000-01-0100:00:00 9999-12-31 23:59:59,timestamp型別取值範圍:1970-01-0100:00:00 2037-12-31 23:59:59

         5.整數型別儘量使用儲存空間小的,整數型別從小到大如下:tinyintsmallintmediumintintbigint;分別使用816243264位儲存空間。整數型別分為有符號的和無符號的(使用屬性UNSIGNED),區別就在於儲存資料的範圍不同,其效能和儲存空間一致。MYSQL可以為整數型別指定長度,例如INT(2),但是指定長度其實是沒有太大意義的,其資料範圍、儲存記憶體和計算都沒影響。

         6.字串型別VARCHARCHAR型別的選優:

                  1.VARCHAR型別用來儲存可變長字串;適用於:字串列的最大長度比平均長度大很多,列的更新很少,這時VARCHAR產生的碎片就不是影響效能的問題。需要注意的就是使用VARCHAR時定義長度很重要,不能過度的大方,更長會消費更多記憶體,所以長度合適最好。

                   2.CHAR型別用來儲存定長字串;適用於:很短的字串,或者所有的值都很接近同一長度。例如MD5儲存的加密資訊。總結:對於經常變更的資料,CHARVARCHAR更好,因為定長的CHAR型別不容易產生碎片。對於非常短的列

CHAR儲存效率更高。

         7.使用列舉(ENUM)替代字串型別;當使用到欄位只有幾個不變的選擇(資料字典項)時可以使用列舉來儲存這幾個不變的字典項,可以減少儲存,提高查詢效率。

.建表規範

         1. 表達是與否概念的欄位,必須使用 is_xxx 的方式命名,資料型別是 unsignedtinyint1 表示是,0 表示否)並且任何欄位如果為非負數,必須是unsigned
         2.
表名、欄位名必須使用小寫字母或數字;禁止出現數字開頭,禁止兩個下劃線中間只出現數字。
         3.
表名不使用複數名詞。
         4.
禁用保留字,如 descrangematchdelayed 等,參考官方保留字。
         5.
唯一索引名為 uk_欄位名;普通索引名則為 idx_欄位名。說明:可讀性強,便於理解,uk_ uniquekeyidx_ index 的簡稱。
         6.
小數型別為 decimal,禁止使用 float double。因為float double 在儲存的時候,存在精度損失的問題,很可能在值的比較時,得到不正確的結果。如果儲存的資料範圍超過 decimal 的範圍,建議將資料拆成整數和小數分開儲存。7.表必備三欄位:id,gmt_create, gmt_modified8.表的命名最好是加上業務名稱_表的作用,避免上雲梯後,再與其它業務表關聯時有混淆。9.庫名與應用名稱儘量一致。10.如果修改欄位含義或對欄位表示的狀態追加時,需要及時更新欄位註釋。11.欄位允許適當冗餘,以提高效能,但是必須考慮資料同步的情況。冗餘欄位應遵循:1)不是頻繁修改的欄位。2)不是 varchar 超長欄位,更不能是 text 欄位。12.單錶行數超過 500 萬行或者單表容量超過 2GB,才推薦進行分庫分表。

三.索引的使用

1.業務上具有唯一特性的欄位,即使是組合欄位,也必須建成唯一索引。說明:不要以為唯一索引影響了insert速度,這個速度損耗可以忽略,但提高查詢速度是明顯的;另外,即使在應用層做了非常完善的校驗和控制,只要沒有唯一索引,根據墨菲定律,必然有髒資料產生。

2.超過三個表禁止join需要join的欄位,資料型別保持絕對一致;多表關聯查詢時,保證被關聯的欄位需要有索引。說明:即使雙表join也要注意表索引、SQL效能。

3.varchar欄位上建立索引時,必須指定索引長度,沒必要對全欄位建立索引,根據實際文字區分度決定索引長度。說明:索引的長度與區分度是一對矛盾體,一般對字串型別資料,長度為20的索引,區分度會高達90%以上,可以使用count(distinct left(列名,索引長度))/count(*)的區分度來確定。

4.頁面搜尋嚴禁左模糊或者全模糊,如果需要請走搜尋引擎來解決。說明:索引檔案具有B-Tree的最左字首匹配特性,如果左邊的值未確定,那麼無法使用此索引。

5.如果有order by的場景,請注意利用索引的有序性。orderby最後的欄位是組合索引的一部分,並且放在索引組合順序的最後,避免出現file_sort的情況,影響查詢效能。

正例:wherea=? and b=? order by c;索引:a_b_c

反例:索引中有範圍查詢,那麼索引有序性無法利用,如:WHEREa>10 ORDER BY b;索引a_b無法排序。

6.利用覆蓋索引來進行查詢操作,來避免回表操作。說明:如果一本書需要知道第11章是什麼標題,會翻開第11章對應的那一頁嗎?目錄瀏覽一下就好,這個目錄就是起到覆蓋索引的作用。

正例:IDB能夠建立索引的種類:主鍵索引、唯一索引、普通索引,而覆蓋索引是一種查詢的一種效果,用explain的結果,extra列會出現:usingindex.

7.利用延遲關聯或者子查詢優化超多分頁場景。說明:MySQL並不是跳過offset行,而是取offset+N行,然後返回放棄前offset行,返回N行,那當offset特別大的時候,效率就非常的低下,要麼控制返回的總頁數,要麼對超過特定閾值的頁數進行SQL改寫。

正例:先快速定位需要獲取的id段,然後再關聯:SELECT a.*FROM1 a, (select id from1 where條件LIMIT 100000,20 ) b where a.id=b.id

8.SQL效能優化的目標:至少要達到range級別,要求是ref級別,如果可以是consts最好。

1consts單表中最多隻有一個匹配行(主鍵或者唯一索引)在優化階段即可讀取到資料。

2ref指的是使用普通的索引。(normal index

3range對索引進範圍檢索。

反例:explain表的結果,type=index,索引物理檔案全掃描,速度非常慢,這個index級別比較range還低,與全表掃描是小巫見大巫。

9.建組合索引的時候,區分度最高的在最左邊。正例:如果where a=? and b=?a列的幾乎接近於唯一值,那麼只需要單建idx_a索引即可。說明:存在非等號和等號混合判斷條件時,在建索引時,請把等號條件的列前置。如:wherea>?and b=?那麼即使a的區分度更高,也必須把b放在索引的最前列。

10.建立索引時避免有如下極端誤解:

1)誤認為一個查詢就需要建一個索引。2)誤認為索引會消耗空間、嚴重拖慢更新和新增速度。3)誤認為唯一索引一律需要在應用層通過先查後插方式解決。

四.SQL優化

1.不要使用count(列名)count(常量)來替代count(*)count(*)就是SQL92定義的標準統計行數的語法,跟資料庫無關,跟NULL和非NULL無關。說明:count(*)會統計值為NULL的行,而count(列名)不會統計此列為NULL值的行。

2.count(distinct col)計算該列除NULL之外的不重複數量。注意count(distinctcol1, col2)如果其中一列全為NULL,那麼即使另一列有不同的值,也返回為0

3.當某一列的值全是NULL時,count(col)的返回結果為0,但sum(col)的返回結果為NULL,因此使用sum()時需注意NPE問題。正例:可以使用如下方式來避免sumNPE問題:SELECTIF(ISNULL(SUM(g)),0,SUM(g))FROMtable;

4.使用ISNULL()來判斷是否為NULL值。注意:NULL與任何值的直接比較都為NULL

說明:1  NULL<>NULL的返回結果是NULL,不是false2  NULL=NULL的返回結果是NULL,不是true3  NULL<>1的返回結果是NULL,而不是true

5.在程式碼中寫分頁查詢邏輯時,若count0應直接返回,避免執行後面的分頁語句。

6.不得使用外來鍵與級聯,一切外來鍵概念必須在應用層解決。

說明:(概念解釋)學生表中的student_id是主鍵,那麼成績表中的student_id則為外來鍵。如果更新學生表中的student_id,同時觸發成績表中的student_id更新,則為級聯更新。外來鍵與級聯更新適用於單機低併發,不適合分散式、高併發叢集;級聯更新是強阻塞,存在資料庫更新風暴的風險;外來鍵影響資料庫的插入速度。

7.禁止使用儲存過程,儲存過程難以除錯和擴充套件,更沒有移植性。

8.IDB資料訂正時,刪除和修改記錄時,要先select,避免出現誤刪除,確認無誤才能提交執行。

9.in操作能避免則避免,若實在避免不了,需要仔細評估in後邊的集合元素數量,控制在1000個之內。

10.因阿里巴巴全球化需要,所有的字元儲存與表示,均以utf-8編碼,那麼字元計數方法注意:說明:SELECTLENGTH("李曉愛你")返回為12SELECT CHARACTER_LENGTH("李曉愛你")返回為4如果要使用表情,那麼使用utfmb4來進行儲存,注意它與utf-8編碼。

11.TRUNCATETABLEDELETE速度快,且使用的系統和事務日誌資源少,但TRUNCATE無事務且不觸發trigger,有可能造成事故,故不建議在開發程式碼中使用此語句。說明:TRUNCATETABLE在功能上與不帶WHERE子句的DELETE語句相同。