文章參考:
https://joonwhee.blog.csdn.net/article/details/106893197問題:如何做慢 SQL 優化?
首先要搞明白慢的原因是什麼:是查詢條件沒有命中索引?還是 load 了不需要的資料列?還是資料量太大?是以優化也是針對這三個方向來的:
首先用 explain 分析語句的執行計劃,檢視使用索引的情況,是不是查詢沒走索引,如果可以加索引解決,優先采用加索引解決。
分析語句,看看是否存在一些導緻索引失效的用法,是否 load 了額外的資料,是否加載了許多結果中并不需要的列,對語句進行分析以及重寫。
如果對語句的優化已經無法進行,可以考慮表中的資料量是否太大,如果是的話可以進行垂直拆分或者水準拆分。
1. 水準拆分與垂直拆分
1.1 水準分表
例:QQ的登入表
假設QQ的使用者有100億,如果隻有一張表,每個使用者登入的時候資料庫都要從這100億中查找,會很慢很慢。如果将這一張表分成100份,每張表有1億條,就小了很多,比如qq0,qq1,qq1...qq99表。
使用者登入的時候,可以将使用者的id%100,那麼會得到0-99的數,查詢表的時候,将表名qq + 取模的數連接配接起來,就建構了表名。比如123456789使用者,取模的89,那麼就到qq89表查詢,查詢的時間将會大大縮短。
1.2 垂直分表
垂直分割指的是:表的記錄并不多,但是字段卻很長,表占用空間很大,檢索表的時候需要執行大量的IO,嚴重降低了性能。這時需要把大的字段拆分到另一個表,并且該表與原表是一對一的關系。
例如:學生答題表student_question,有如下5個字段:
Id,name,分數,題目,回答。其中題目和回答是比較大的字段,Id,name,分數比較小。
如果我們隻想查詢id為8的學生的分數:select 分數 from tt where id = 8;
雖然隻是查詢分數,但是題目和回答這兩個大字段也是要被掃描的,很消耗性能。然而我們隻需要關心分數,并不想查詢題目和回答。這種情況下就可以使用垂直分割。
我們可以把題目單獨放到一張表中,通過id與tt表建立一對一的關系,同樣将回答單獨放到一張表中。這樣我們查詢student_question中的分數的時候就不會掃描題目和回答這兩個大字段了。
1.3 小結
水準分割是表中資料量過大,嚴重影響查詢效率時,将1張資料量龐大的表按照某種條件進行拆分成N張名稱不同字段和資料類型相同的表。
垂直分割是表中記錄數不多,但是字段很多,且字段長,表占用空間大的情況下,把大的字段拆分到另一個表,并且該表與原表是一對一的關系。
2. 主從複制
參考文章:MySQL主從複制讀寫分離,看這篇就夠了
2.1 MySQL主從複制介紹
MySQL主從複制涉及到三個線程,一個運作在主節點(Log Dump Thread),其餘兩個(I/O Thread,SQL Thread)運作在從節點,如下圖所示

主從複制預設是異步的模式,具體過程如下:
從節點上的 I/O 線程連接配接主節點,請求讀取主庫的二進制日志檔案(bin log 日志)的指定位置(bin log position)之後的日志内容;
主節點線程接收到來自從節點 I/O 線程的請求後,讀取主節點中的二進制日志檔案(bin log 日志)的指定位置之後的日志資訊,傳回給從節點。
傳回給從節點的内容資訊中除了日志所包含的資訊之外,還包括本次傳回的資訊的 bin-log file(二進制日志檔案) 以及 bin-log position(讀取的位置);
從節點的 I/O 線程接收到内容後,将接收到的日志内容更新到 relay log (中繼日志)中,并将讀取到的 bin log file(檔案名)和position(位置)儲存到 master-info 檔案中,以便在下一次讀取的時候能夠清楚的告訴 Master “我需要從某個bin-log 的哪個位置開始往後的日志内容”
從節點的 SQL 線程檢測到 relay-log 中新增加了内容後,會解析 relay-log 的内容,并在本資料庫中執行。
2.2 異步複制,主庫當機後,資料可能丢失?
可以使用半同步複制或全同步複制。
半同步複制:
修改語句寫入bin log後,不會立即給用戶端傳回結果。而是首先通過log dump 線程将 binlog 發送給從節點,從節點的 I/O 線程收到 binlog 後,寫入到 relay log,然後傳回 ACK 給主節點,主節點 收到 ACK 後,再傳回給用戶端成功。
半同步複制的特點:
確定事務送出後 binlog 至少傳輸到一個從庫,不保證從庫應用完這個事務的 binlog。
性能有一定的降低,響應時間會更長。
網絡異常或從庫當機,卡主主庫,直到逾時或從庫恢複。
全同步複制:主節點和所有從節點全部執行了該事務并确認才會向用戶端傳回成功。因為需要等待所有從庫執行完該事務才能傳回,是以全同步複制的性能必然會收到嚴重的影響。
2.3 主庫寫壓力大,從庫複制很可能出現延遲?
可以使用并行複制(并行是指從庫多個SQL線程并行執行 relay log),解決從庫複制延遲的問題。
MySQL 5.7 中引入基于組送出的并行複制,其核心思想:一個組送出的事務都是可以并行回放,因為這些事務都已進入到事務的 prepare 階段,則說明事務之間沒有任何沖突(否則就不可能送出)。
判斷事務是否處于一個組是通過 last_committed 變量,last_committed 表示事務送出的時候,上次事務送出的編号,如果事務具有相同的 last_committed,則表示這些事務都在一組内,可以進行并行的回放。