深入理解MySQL系列之優化
查詢語句優化
-
選取最適用的欄位屬性。設定合適表中欄位的寬度,儘量把欄位設定為NOTNULL,這樣在將來執行查詢的時候,資料庫不用去比較NULL值。對於某些文字欄位,例如“省份”或者“性別”,我們可以將它們定義為ENUM型別。因為在MySQL中,ENUM型別被當作數值型資料來處理,而數值型資料被處理起來的速度要比文字型別快得多
-
使用連線(JOIN)來代替子查詢
-
使用聯合(UNION)來代替手動建立的臨時表
-
使用事務保證資料一致性和完整性
-
鎖定表
-
使用外來鍵
-
使用索引
-
應儘量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。
-
應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:select id from t where num is null。可以在num上設定預設值0,確保表中num列沒有null值,然後這樣查詢:select id from t where num=0
-
很多時候用 exists 代替 in 是一個好的選擇
-
用Where子句替換HAVING 子句 因為HAVING 只會在檢索出所有記錄之後才對結果集進行過濾
-
先進行排序再使用limit進行排序(https://mp.weixin.qq.com/s/F5g0tKo__63ykVZfez38Dw
-
注意隱式轉換,函式作用於表字段,會使得索引失效。
-
不能利用索引進行混合排序
索引優化
建議建立索引列
-
在經常需要搜尋的列上,可以加快搜索的速度;
-
在作為主鍵的列上,強制該列的唯一性和組織表中資料的排列結構;
-
在經常用在連線的列上,這些列主要是一些外來鍵,可以加快連線的速度;
-
在經常需要根據範圍進行搜尋的列上建立索引,因為索引已經排序,其指定的範圍是連續的;在經常需要排序的列上建立索引,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;
-
在經常使用在WHERE子句中的列上面建立索引,加快條件的判斷速度。
不建議建立索引列
-
對於那些在查詢中很少使用或者參考的列不應該建立索引。這是因為,既然這些列很少使用到,因此有索引或者無索引,並不能提高查詢速度。相反,由於增加了索引,反而降低了系統的維護速度和增大了空間需求。
-
對於那些只有很少資料值的列也不應該增加索引。這是因為,由於這些列的取值很少,例如人事表的性別列,在查詢的結果中,結果集的資料行佔了表中資料行的很大比例,即需要在表中搜索的資料行的比例很大。增加索引,並不能明顯加快檢索速度。
-
對於那些定義為text, image和bit資料型別的列不應該增加索引。這是因為,這些列的資料量要麼相當大,要麼取值很少。
-
當修改效能遠遠大於檢索效能時,不應該建立索引。這是因為,修改效能和檢索效能是互相矛盾的。當增加索引時,會提高檢索效能,但是會降低修改效能。當減少索引時,會提高修改效能,降低檢索效能。因 此,當修改效能遠遠大於檢索效能時,不應該建立索引。
索引優化:
-
最左字首匹配原則,上面講到了
主鍵外檢一定要建索引
對 where,on,group by,order by 中出現的列使用索引
儘量選擇區分度高的列作為索引,區分度的公式是count(distinct col)/count(*),表示欄位不重複的比例,比例越大我們掃描的記錄數越少,唯一鍵的區分度是1,而一些狀態、性別欄位可能在大資料面前區分度就是0 -
對較小的資料列使用索引,這樣會使索引檔案更小,同時記憶體中也可以裝載更多的索引鍵
-
索引列不能參與計算,保持列“乾淨”,比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很簡單,b+樹中存的都是資料表中的欄位值,但進行檢索時,需要把所有元素都應用函式才能比較,顯然成本太大。所以語句應該寫成create_time = unix_timestamp(’2014-05-29’);
為較長的字串使用字首索引 -
儘量的擴充套件索引,不要新建索引。比如表中已經有a的索引,現在要加(a,b)的索引,那麼只需要修改原來的索引即可
-
不要過多建立索引, 權衡索引個數與DML之間關係,DML也就是插入、刪除資料操作。這裡需要權衡一個問題,建立索引的目的是為了提高查詢效率的,但建立的索引過多,會影響插入、刪除資料的速度,因為我們修改的表資料,索引也需要進行調整重建
-
對於like查詢,”%”不要放在前面。
SELECT * FROM table WHERE uname LIKE'xx%' -- 走索引
SELECT * FROM table WHERE uname LIKE "%xx%" -- 不走索引 -
查詢where條件資料型別不匹配也無法使用索引
字串與數字比較不使用索引;
CREATE TABLEa(achar(10));
EXPLAIN SELECT * FROMaWHEREa="1" – 走索引
EXPLAIN SELECT * FROM a WHERE a=1 – 不走索引
正則表示式不使用索引,這應該很好理解,所以為什麼在SQL中很難看到regexp關鍵字的原因
資料庫結構優化
-
正規化優化: 比如消除冗餘(節省空間。。)
-
反正規化優化:比如適當加冗餘等(減少join)
-
拆分表: 垂直拆分和水平拆分。對於欄位較多的表,如果某些欄位使用頻率較低,此時應當,將其分離出來從而形成新的表,
-
增加中間表: 對於將大量連線查詢的表可以建立中間表,從而減少在查詢時造成的連線耗時.
-
增加冗餘欄位:
類似於建立中間表,增加冗餘也是為了減少連線查詢.
分析表、檢查表、優化表
分析表主要是分析表中關鍵字的分佈,檢查表主要是檢查表中是否存在錯誤,優化表主要是消除刪除或更新造成的表空間浪費.
1.分析表: 使用 ANALYZE 關鍵字,如ANALYZE TABLE user;
2.檢查表: 使用 CHECK關鍵字,如CHECK TABLE user [option](option 只對MyISAM有效)
3.優化表:使用OPTIMIZE關鍵字,如OPTIMIZE [LOCAL|NO_WRITE_TO_BINLOG] TABLE user;
LOCAL|NO_WRITE_TO_BINLOG都是表示不寫入日誌.,優化表只對VARCHAR,BLOB和TEXT有效,通過OPTIMIZE TABLE語句可以消除檔案碎片,在執行過程中會加上只讀鎖.
伺服器硬體優化
- 硬體伺服器優化
- 配置多核心和頻率高的cpu,多核心可以執行多個執行緒
- 配置大記憶體,提高記憶體,即可提高快取區容量,因此能減少磁碟I/O時間,從而提高響應速度.
- 配置高速磁碟或合理分佈磁碟:高速磁碟提高I/O,分佈磁碟能提高並行操作的能力.
- 優化資料庫引數
優化資料庫引數可以提高資源利用率,從而提高MySQL伺服器效能.MySQL服務的配置引數都在my.cnf或my.ini,下面列出效能影響較大的幾個引數.
key_buffer_size:索引緩衝區大小
table_cache:能同時開啟表的個數
query_cache_size和query_cache_type:前者是查詢緩衝區大小,後者是前面引數的開關,0表示不使用緩衝區,1表示使用緩衝區,但可以在查詢中使用SQL_NO_CACHE表示不要使用緩衝區,2表示在查詢中明確指出使用緩衝區才用緩衝區,即SQL_CACHE.
sort_buffer_size:排序緩衝區
-
分庫分表
對系統做分庫分表 + 讀寫分離,也就是把一個庫拆分為多個庫,部署在多個數據庫服務上,這時作為主庫承載寫入請求。然後每個主庫都掛載至少一個從庫,由從庫來承載讀請求。 -
快取叢集
在寫資料庫的時候同時寫一份資料到快取叢集裡,然後用快取叢集來承載大部分的讀請求。
explain 執行計劃
慢查詢分析
https://mp.weixin.qq.com/s/1r6lFQE4pxeo0zsV3yVkXg
mysql> show variables like 'long%';
long_query_time | 10.000000
mysql> set long_query_time=1;
mysql> show variables like 'slow%';
slow_launch_time | 2
slow_query_log | ON
slow_query_log_file | /tmp/slow.log
mysql> set global slow_query_log='ON'
日誌分析工具mysqldumpslow
得到返回記錄集最多的10個SQL。
mysqldumpslow -s r -t 10 /database/mysql/mysql06_slow.log
得到訪問次數最多的10個SQL
mysqldumpslow -s c -t 10 /database/mysql/mysql06_slow.log
得到按照時間排序的前10條裡面含有左連線的查詢語句
mysqldumpslow -s t -t 10 -g “left join” /database/mysql/mysql06_slow.log
另外建議在使用這些命令時結合 | 和more 使用 ,否則有可能出現刷屏的情況。
mysqldumpslow -s r -t 20 /mysqldata/mysql/mysql06-slow.log | more
其他一些效能排除命令
-
top檢視記憶體、cpu
-
執行緒堆疊資訊
printf "%x\n" pid
jstack pid|grep -A 30 "nid=0x1df9"
-
檢查資料庫執行緒
show full processlist -
檢視儲存引擎狀態:show engine InnoDB status;
-
檢視最大連線數與響應最大連線數
show variables like '%max_connections%';
show variables like '%max_user_connections%';
更全面維度思考優化
https://mp.weixin.qq.com/s/-RpDVsOVU5Wyqmy7XWsEow
https://mp.weixin.qq.com/s/Puh-JGb5Y3kd_Dlmga1zVw
https://mp.weixin.qq.com/s/F5g0tKo__63ykVZfez38Dw
https://mp.weixin.qq.com/s/-RpDVsOVU5Wyqmy7XWsEow
https://mp.weixin.qq.com/s/ZBgv-s-_ojWMiTZYTVx-iQ