精品專欄
引言
大家在面試的時候,是否遭遇過,面試官詢問
你們是如何進行資料庫最佳化的?
那這個問題應該怎麼答呢?其實寫這個題材的原因是我這幾天看到各公眾號轉的一篇資料庫調優的知識(不上連結了),我就稍微翻了幾下,上面動不動就來說要對資料庫進行水平拆分,我就想反問各位讀者,你們幾個人經歷過水平拆分?現在很多文章,實踐性實在太差,只能說純理論分析。
這篇文章最早來自知乎的一個提問,我在其基礎上完善了一下。
第一階段 最佳化sql和索引
這才是調優的第一階段啊,為什麼呢?
因為這一步成本最低啊,不需要加什麼中介軟體。你沒經過索引最佳化和SQL最佳化,就來什麼水平拆分,這不是坑人麼。
那步驟是什麼樣呢?我說個大概
-
用慢查詢日誌定位執行效率低的
SQL
陳述句 -
用
explain
分析SQL
的執行計劃 -
確定問題,採取相應的最佳化措施,建立索引啊,等
我就不舉例了,因為如何最佳化SQL的文章,一抓一大把,再貼過來,讀者看著也累。
第二階段 搭建快取
在最佳化sql無法解決問題的情況下,才考慮搭建快取。畢竟你使用快取的目的,就是將複雜的、耗時的、不常變的執行結果快取起來,降低資料庫的資源消耗。
這裡需要註意的是:搭建快取後,系統的複雜性增加了。你需要考慮很多問題,比如:
-
快取和資料庫一致性問題?(比如是更快取,還是刪快取),這點可以看我的一篇文章《資料庫和快取雙寫一致性方案解析》。
-
快取擊穿、快取穿透、快取雪崩問題如何解決?是否有做快取預熱的必要。不過我猜,大部分中小公司應該都沒考慮。這點可以看我的另一篇《分散式之redis複習精講》
第三階段 讀寫分離
快取也搞不定的情況下,搞主從複製,上讀寫分離。在應用層,區分讀寫請求。或者利用現成的中介軟體 mycat
或者 altas
等做讀寫分離。
需要註意的是,只要你敢說你用了主從架構,有三個問題,你要準備:
1.主從的好處?
回答:實現資料庫備份,實現資料庫負載均衡,提高資料庫可用性
2.主從的原理?
回答:如圖所示(圖片不是自己畫的,偷懶了)
主庫有一個 logdump
執行緒,將 binlog
傳給從庫
從庫有兩個執行緒,一個I/O執行緒,一個SQL執行緒,I/O執行緒讀取主庫傳過來的 binlog
內容並寫入到 relay log
,SQL執行緒從 relay log
裡面讀取內容,寫入從庫的資料庫。
3.如何解決主從一致性?
回答:這個問題,我不建議在資料庫層面解決該問題。根據 CAP 定理,主從架構本來就是一種高可用架構,是無法滿足一致性的。 哪怕你採用同步複製樣式或者半同步複製樣式,都是弱一致性,並不是強一致性。所以,推薦還是利用快取,來解決該問題。
步驟如下:
-
自己透過測試,計算主從延遲時間,建議mysql版本為5.7以後,因為mysql自5.7開始,多執行緒複製功能比較完善,一般能保證延遲在1s內。不過話說回來,mysql現在都出到8.x了,還有人用5.x的版本麼。
-
資料庫的寫操作,先寫資料庫,再寫cache,但是有效期很短,就比主從延時的時間稍微長一點。
-
讀請求的時候,先讀快取,快取存在則直接傳回。如果快取不存在(這時主從同步已經完成),再讀資料庫。
第四階段 利用分割槽表
說句實在話,你們面試的時候,其實可以略過這個階段。因為很多網際網路公司都不建議用分割槽表,我自己也不太建議用分割槽表,採用這個分割槽表,坑太多。
這裡取用一下其他文章的回答:
什麼是mysql的分割槽表?
回答:所有資料還在一個表中,但物理儲存根據一定的規則放在不同的檔案中。這個是mysql支援的功能,業務程式碼不需要改動,但是sql陳述句需要改動,sql條件需要帶上分割槽的列。
缺點
-
分割槽鍵設計不太靈活,如果不走分割槽鍵,很容易出現全表鎖
-
在分割槽表使用
ALTER TABLE
…ORDER BY
,只能在每個分割槽內進行orderby
。 -
分割槽表的分割槽鍵建立索引,那麼這個索引也將被分割槽。分割槽鍵沒有全域性索引一說。
-
自己分庫分表,自己掌控業務場景與訪問樣式,可控。分割槽表,研發寫了一個sql,都不確定該去哪個分割槽查,不太可控。 …不列舉了,不推薦
第五階段 垂直拆分
上面四個階段都沒搞定,就來垂直拆分了。垂直拆分的複雜度還是比水平拆分小的。將你的表,按模組拆分為不同的小表。大家應該都看過《大型網站架構演變之路》,這種型別的文章或者書籍,基本都有提到這一階段。
如果你有幸能夠在什麼運營商、銀行等公司上班,你會發現他們一個表,幾百個欄位都是很常見的事情。所以,應該要進行拆分,拆分原則一般是如下三點:
-
把不常用的欄位單獨放在一張表。
-
把常用的欄位單獨放一張表
-
經常組合查詢的列放在一張表中(聯合索引)。
第六階段 水平拆分
OK,水平拆分是最麻煩的一個階段,拆分後會有很多的問題,我再強調一次,水平拆分一定是最最最最後的選擇。從某種意義上,我覺得還不如垂直拆分。因為你用垂直拆分,分成不同模組後,發現單模組的壓力過大,你完全可以給該模組單獨做最佳化,例如提高該模組的機器配置等。如果是水平拆分,拆成兩張表,程式碼需要變動,然後發現兩張表還不行,再變程式碼,再拆成三張表的?水平拆分後,各模組間耦合性太強,成本太大,慎重。
多執行緒:為什麼在while迴圈中加入System.out.println,執行緒可以停止
你真的瞭解try{ return }finally{}中的return?
END
>>>>>> 加群交流技術 <<<<<<