BlackFlame33

BlackFlame33

若无力驾驭,自由便是负担。个人博客 https://blackflame33.cn/

MySQL 的優化

MySQL 的優化一般是針對查詢操作來說的,首先我們得知道 SQL 查詢需要經過哪些操作。

iShot_2023-02-28_08.58.53

一、連接配置優化#

1.1 服務端優化#

修改默認的服務端的最大連接數(系統默認一般是 151)和默認的客戶端超時時間(默認的一般是 8 小時),當然若無必要不需要修改。以下是查詢它們的系統默認值的方式:

iShot_2023-02-28_09.11.29

iShot_2023-02-28_09.13.11

1.2 客戶端優化#

對於客戶端的優化,我們是不希望客戶頻繁的創建和銷毀連接的,這時我們就需要用數據庫連接池來復用連接以減少數據庫資源的開銷。當前最流行的數據庫連接池就是 Druid 和 HikariCP。DBCP 和 C3P0 已經。。。

當然我們需要注意連接池大小的設置並不是越大越好。因為每個連接都需要一個線程去維護,當線程數超過 CPU 個數時,就需要頻繁的切換線程的上下文從而導致性能的開銷變大。

二、架構優化#

2.1. 使用緩存#

在查詢和數據庫之間加緩存,放一些不會經常發生變化的數據。

2.2 讀寫分離#

這種方式主要是降低伺服器的壓力。使用伺服器集群,其中一台伺服器作為 master 節點,其他伺服器作為 slave 節點。當主伺服器的數據改變之後,其他的伺服器也需要進行同步,master 節點只負責增刪改的操作,slave 節點負責查詢。這種方式很好地降低了伺服器的壓力。

2.3 分庫分表#

2.3.1 垂直分庫#

iShot_2023-02-28_14.08.52

在單體數據庫的基礎上垂直切幾刀,按照業務邏輯將不同的表分到不同的數據庫中,並且這些數據庫是在不同的伺服器上面,這就是垂直分庫。

iShot_2023-02-28_14.12.03

2.3.2 垂直分表#

iShot_2023-02-28_14.03.01

垂直分表就是在單表的基礎上垂直切一刀(或幾刀),將一個表的多個字段拆成若干個小表。這種操作需要根據具體業務來進行判斷,通常會把經常使用的字段(熱字段)分成一個表,不經常使用或者不立即使用的字段(冷字段)分成一個表。這不僅解決了單一表數據量過大的問題而且提升了查詢速度。

iShot_2023-02-28_14.05.19

拿上圖舉例:通常情況下商品的詳細信息都比較長,且查看商品列表時往往不需要立即展示商品詳細(一般都是點擊詳細按鈕才會進行顯示),而是會將商品更重要的信息(價格等) 展示出來。按照這個業務邏輯,我們將原來的商品表做了垂直分表。

2.3.3 水平分庫#

經過垂直分庫後,數據庫性能問題得到一定程度的解決。可隨著業務量的增長,單體數據庫中存儲的數據已經超出預估,單台伺服器已經無法支撐,但從業務角度來看,此時已經無法垂直分庫了。這時就可以嘗試按照一定的規則水平分庫,比如說(將 id 為單數的和 id 為雙數的商品信息分別放在兩個庫中)。

iShot_2023-02-28_14.14.57

iShot_2023-02-28_14.15.44

2.3.4 水平分表#

把單張表的數據按照一定的規則(行話叫分片規則)保存到多個數據表上,橫著給數據表來一刀(或幾刀),就是水平分表了。

iShot_2023-02-28_14.19.27

iShot_2023-02-28_14.20.14

2.3.5 總結#

水平分表,主要是為了解決存儲的瓶頸;垂直分表,主要是為了減輕並發壓力。

2.4 消息隊列消峰#

通常情況下,用戶的請求會直接訪問數據庫,如果同一時刻在線用戶數量非常龐大,極有可能壓垮數據庫(參考明星出軌或公布戀情時微博的狀態)。

這種情況下可以通過使用消息隊列降低數據庫的壓力,不管同時有多少個用戶請求,先存入消息隊列,然後系統有條不紊地從消息隊列中消費請求。

三、優化器 ——SQL 分析與優化#

到了這一步就已經來到了解析器和優化器的地盤了。一般來說,你的 SQL 語法沒有問題,解析器就不會出現問題。此外,為了防止你寫的 SQL 運行效率低,優化器會自動做一些優化,但如果實在是太爛,優化器也救不了你了,只能眼睜睜地看著你的 SQL 查詢淪為慢查詢

3.1 慢查詢#

顧名思義,慢查詢就是很慢的查詢。使用以下命令可以查看 mysql 的滿查詢狀態:

iShot_2023-02-28_22.42.48

輸出以下的命令查看滿的標準:

iShot_2023-02-28_22.44.30

3.2 查看運行中的線程#

運行 show full processlist 查看 mysql 運行的所有線程

iShot_2023-02-28_23.03.44

其中,

  • Id: 線程的唯一標誌,可以使用 Id 殺死指定線程;
  • User: 啟動這個線程的用戶,普通賬戶只能查看自己的線程;
  • Host: 哪個 ip 和端口發起的連接;
  • db: 線程操作的數據庫;
  • Command: 線程的命令;
  • Time: 操作持續時間,單位秒;
  • State: 線程的狀態;
  • Info: SQL 語句的前 100 個字符。

3.3 查看伺服器的運行狀態#

使用SHOW STATUS查看 MySQL 伺服器的運行狀態,有sessionglobal兩種作用域

iShot_2023-02-28_23.12.45

以上代碼是查看 select 的次數

3.4 查看存儲引擎運行信息#

SHOW ENGINE INNODB STATUS;

image

3.5 EXPLAIN 執行計劃#

所謂的計劃就是我們的 MySQL 中的優化器會不會幫我們把我們寫的 sql 語句優化(比如外連接改內連接查詢,子查詢優化為連接查詢...),優化器針對此條 SQL 的執行對哪些索引進行了成本估算,並最終決定採用哪個索引(或者最終選擇不用索引,而是全表掃描),優化器對單表執行的策略是什麼,等等等等。

explain 執行計劃以前通常用在查詢語句上,不過現在也可以用在增刪改的語句中了

3.6 SQL 與索引優化#

3.6.1 SQL 優化#

  • 使用小表驅動大表;用 join 改寫子查詢(嵌套查詢);或者改成 union
  • 連接查詢中,儘量減少驅動表的扇出(記錄數),訪問被驅動表的成本要儘量低,儘量在被驅動表的連接列上建立索引,降低訪問成本;被驅動表的連接列最好是該表的主鍵或者是唯一二級索引列,這樣被驅動表的成本會降到更低;
  • 大偏移量的 limit,先過濾再排序。

iShot_2023-03-01_23.06.18

3.6.2 索引優化#

1. 能不回表就不回表,如果回表就減少回表次數(回表是有代價的,有可能會從外存中加載數據頁);

2. 使用索引覆蓋。

四、存儲結構與表結構#

4.1 選擇存儲引擎#

建議根據不同的業務選擇不同的存儲引擎,例如:

  • 查詢操作、插入操作多的業務表,推薦使用MyISAM
  • 臨時表使用Memory
  • 並發數量大、更新多的業務選擇使用InnoDB
  • 不知道選啥直接默認。

4.2 優化字段#

原則:使用可以正確存儲數據的最小的數據類型

4.2.1 整數類型#

MySQL 提供了 6 種整數類型,分別是

  • tinyint
  • smallint
  • mediumint
  • int
  • integer
  • bigint

4.2.2 字符類型#

如果是不確定字段長度,無腦選 varchar,因為 varchar 會有額外的空間記錄該字段的長度,但是如果字段長度固定的,儘量選取 char,這會節省不少內存空間。

4.2.3 非空#

非空字段儘量設置成NOT NULL,並提供默認值,或者使用特殊值代替NULL。因為NULL類型的存儲和優化都會存在性能不佳的問題。

4.2.4 不要使用外鍵、觸發器和視圖功能(特別是大數據量時,碰一個就 G)#

這也是「阿里巴巴開發手冊」中提到的原則。原因有三個:

  1. 降低了可讀性,檢查代碼的同時還得查看數據庫的代碼;
  2. 把計算的工作交給程序 (業務層),數據庫只做好存儲的工作,並把這件事情做好;
  3. 一般大數據量的時候為了解決存儲瓶頸,會水平分表;
  4. 觸發器可以理解為及時捕捉數據的變化,並做相應的處理,設計初衷非常好,但是劣勢掩蓋了優勢,增刪改操作會頻繁的觸發觸發器,導致資源消耗特別大;
  5. 數據的完整性校驗的工作應該由開發者完成,而不是依賴於外鍵,一旦用了外鍵,你會發現測試的時候隨便刪點垃圾數據都變得異常艱難(外鍵約束,會導致表結構非常混亂,還可能會循環約束)。

4.2.5 圖片、音頻、視頻存儲#

存儲它們的地址即可。

4.2.6 大字段拆分和數據冗餘#

大字段拆分其實就是前面說過的垂直分表,把不常用的字段或者數據量較大的字段拆分出去,避免列數過多和數據量過大,尤其是習慣編寫SELECT *的情況下,列數多和數據量大導致的問題會被嚴重放大!

字段冗餘原則上不符合數據庫設計範式,但是卻非常有利於快速檢索。比如,合同表中存儲客戶 id 的同時可以冗餘存儲客戶姓名,這樣查詢時就不需要再根據客戶 id 獲取用戶姓名了。因此針對業務邏輯適當做一定程度的冗餘也是一種比較好的優化技巧。(一般用於查詢多修改少的場景)

五、業務優化#

嚴格來說,業務方面的優化已經不算是 MySQL 調優的手段了,但是業務的優化卻能非常有效地減輕數據庫訪問壓力,這方面一個典型例子就是淘寶,下面舉幾個簡單例子給大家提供一下思路:

  1. 預售分流:以往都是雙 11 當晚開始買買買的模式,最近幾年雙 11 的預售戰線越拉越長,提前半個多月就開始了,而且各種定金紅包模式層出不窮,這種方式叫做預售分流。這樣做可以分流客戶的服務請求,不必等到雙十一的凌晨一股腦地集體下單;
  2. 降級策略:雙十一的凌晨你或許想查詢當天之外的訂單,但是卻查詢失敗;甚至支付寶裡的小雞的口糧都被延遲發放了,這是一種降級策略,集結不重要的服務的計算資源,用來保證當前最核心的業務;
  3. 雙十一的時候支付寶極力推薦使用花唄支付,而不是銀行卡支付,雖然一部分考量是提高軟件粘性,但是另一方面,使用餘額寶實際使用的阿里內部伺服器,訪問速度快,而使用銀行卡,需要調用銀行接口,相比之下操作要慢了許多。
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。