1. 程式人生 > 實用技巧 >深入理解MySQL系列之優化

深入理解MySQL系列之優化

查詢語句優化
  1. 選取最適用的欄位屬性。設定合適表中欄位的寬度,儘量把欄位設定為NOTNULL,這樣在將來執行查詢的時候,資料庫不用去比較NULL值。對於某些文字欄位,例如“省份”或者“性別”,我們可以將它們定義為ENUM型別。因為在MySQL中,ENUM型別被當作數值型資料來處理,而數值型資料被處理起來的速度要比文字型別快得多

  2. 使用連線(JOIN)來代替子查詢

  3. 使用聯合(UNION)來代替手動建立的臨時表

  4. 使用事務保證資料一致性和完整性

  5. 鎖定表

  6. 使用外來鍵

  7. 使用索引

  8. 應儘量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。

  9. 應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:select id from t where num is null。可以在num上設定預設值0,確保表中num列沒有null值,然後這樣查詢:select id from t where num=0

  10. 很多時候用 exists 代替 in 是一個好的選擇

  11. 用Where子句替換HAVING 子句 因為HAVING 只會在檢索出所有記錄之後才對結果集進行過濾

  12. 先進行排序再使用limit進行排序(https://mp.weixin.qq.com/s/F5g0tKo__63ykVZfez38Dw

    )

  13. 注意隱式轉換,函式作用於表字段,會使得索引失效。

  14. 不能利用索引進行混合排序

索引優化

建議建立索引列

  • 在經常需要搜尋的列上,可以加快搜索的速度;

  • 在作為主鍵的列上,強制該列的唯一性和組織表中資料的排列結構;

  • 在經常用在連線的列上,這些列主要是一些外來鍵,可以加快連線的速度;

  • 在經常需要根據範圍進行搜尋的列上建立索引,因為索引已經排序,其指定的範圍是連續的;在經常需要排序的列上建立索引,因為索引已經排序,這樣查詢可以利用索引的排序,加快排序查詢時間;

  • 在經常使用在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關鍵字的原因

資料庫結構優化
  1. 正規化優化: 比如消除冗餘(節省空間。。)

  2. 反正規化優化:比如適當加冗餘等(減少join)

  3. 拆分表: 垂直拆分和水平拆分。對於欄位較多的表,如果某些欄位使用頻率較低,此時應當,將其分離出來從而形成新的表,

  4. 增加中間表: 對於將大量連線查詢的表可以建立中間表,從而減少在查詢時造成的連線耗時.

  5. 增加冗餘欄位:
    類似於建立中間表,增加冗餘也是為了減少連線查詢.

分析表、檢查表、優化表

分析表主要是分析表中關鍵字的分佈,檢查表主要是檢查表中是否存在錯誤,優化表主要是消除刪除或更新造成的表空間浪費.

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語句可以消除檔案碎片,在執行過程中會加上只讀鎖.

伺服器硬體優化
  1. 硬體伺服器優化
  • 配置多核心和頻率高的cpu,多核心可以執行多個執行緒
  • 配置大記憶體,提高記憶體,即可提高快取區容量,因此能減少磁碟I/O時間,從而提高響應速度.
  • 配置高速磁碟或合理分佈磁碟:高速磁碟提高I/O,分佈磁碟能提高並行操作的能力.
  1. 優化資料庫引數

優化資料庫引數可以提高資源利用率,從而提高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:排序緩衝區

  1. 分庫分表
    對系統做分庫分表 + 讀寫分離,也就是把一個庫拆分為多個庫,部署在多個數據庫服務上,這時作為主庫承載寫入請求。然後每個主庫都掛載至少一個從庫,由從庫來承載讀請求。

  2. 快取叢集

在寫資料庫的時候同時寫一份資料到快取叢集裡,然後用快取叢集來承載大部分的讀請求。

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

其他一些效能排除命令
  1. top檢視記憶體、cpu

  2. 執行緒堆疊資訊

printf "%x\n" pid
jstack pid|grep -A 30 "nid=0x1df9"

  1. 檢查資料庫執行緒
    show full processlist

  2. 檢視儲存引擎狀態:show engine InnoDB status;

  3. 檢視最大連線數與響應最大連線數

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