MySQL 資料庫連線原理和效能優化
常見的 MySQL 客戶端
MySQL 服務端啟動之後,就可以通過客戶端建立與服務端的連線,然後傳送查詢/更新請求了。
我們可以通過 MySQL 安裝目錄 bin
目錄下的 mysql
二進位制檔案在終端視窗通過命令列建立與 MySQL 服務端的連線,也可以通過圖形化客戶端軟體建立這種連線(比如 MySQL Workbench、Navicat For MySQL、DataGrip、TablePlus、Sequel Pro 等),此外,我們在 PHP、Go、Python、Java 這些後端程式語言中使用的資料庫 SDK 也是一種 MySQL 客戶端,只不過這些 SDK 對資料庫連線做了封裝而已。
以上都是日常開發過程中經常打交道的 MySQL 客戶端,這裡,為了更接近底層原理,我們使用 mysql
mysql 命令解析
我們可以通過如下命令格式建立資料庫連線:
1mysql -h主機名 -P埠號 -u使用者名稱 -p密碼
注:如果 MySQL 服務端監聽的埠號是預設的
3306
的話,可以省略埠號(如果想要使用其他埠號,可以在啟動服務端時通過命令列引數或者配置檔案指定)。
我們以預設的 root
使用者為例,在終端視窗通過如下命令即可建立與本地 MySQL 服務端的連線:
這裡我們通過 -h
指定 MySQL 服務端所在的主機 IP 地址,這裡是本地 IP 地址 127.0.0.1
,通過 -u
指定使用者名稱是 root
-p
指定對應的密碼是 root
。
雖然可以通過這種方式比較便捷地指定密碼資訊,但是如果是連線到生產環境 MySQL 伺服器,則不建議這麼做,因為這樣會導致密碼的洩露,取而代之地,可以通過如下這種互動式方式輸入密碼發起連線請求:
這樣一來,輸入的密碼資訊就不可見了。
連線成功後,我們就可以通過這個互動式介面來操作 MySQL 資料庫了。在進行下一步操作之前,我們先來看看 MySQL 客戶端是如何建立與服務端的連線的。
資料庫連線過程
不管是 MySQL 服務端還是客戶端,本質上都是計算機的程序,所以這個連線過程和通過瀏覽器(HTTP 客戶端)請求指定網站(HTTP 服務端)連線建立過程並無二致,都是程序之間的通訊。只不過後者是 HTTP 請求,基於 HTTP 協議,而前者是 TCP 請求,基於 TCP 協議。
注:雖然 MySQL 也支援 TCP 請求之外的其他連線建立方式,比如 Unix 套接字,但是我們日常使用的通常都是基於 TCP 連線的,這裡就以此為例進行講解。
學院君在網路協議的傳輸層協議中已經介紹過 TCP 通訊的原理,既然是 TCP 請求,那麼通訊的雙方 —— MySQL 客戶端和服務端需要具備必要的程序資訊:源 IP 地址、源埠號、目標 IP 地址、目標埠號,這樣才能建立可靠連線,這裡的目標 IP 地址就是 MySQL 服務端所在的 IP 地址,上面的示例是 127.0.0.1
,目標埠號就是 MySQL 服務端程序的埠號,預設是 3306
。
所以從這個角度來說,通過 mysql
命令建立與服務端的連線和通訊,必須指定服務端主機(IP 地址或者主機名)和埠號(預設是 3306,可以省略,但如果不是 3306,則必須指定)。
在完成經典的 TCP 握手後,服務端就要開始認證你的身份,這個時候用的就是你輸入的使用者名稱和密碼:
- 如果使用者名稱或密碼不對,就會收到一個
Access denied for user
的錯誤,然後客戶端程式結束執行: - 如果使用者名稱密碼認證通過,聯結器會到許可權表裡面查出你擁有的許可權,之後,這個連線裡面的許可權判斷邏輯,都將依賴於此時讀到的許可權。這就意味著,一個使用者成功建立連線後,即使對這個使用者的許可權做了修改,也不會影響已經存在連線的許可權,只有新建的連線才會使用新的許可權設定。
資料庫連線狀態
連線完成後,如果你沒有後續的動作,這個連線就處於空閒狀態,你可以在 show processlist
命令中看到它:
其中的 Command 列顯示為 Sleep 的行,表示一個空閒連線。
客戶端如果太長時間沒動靜,聯結器就會自動將它斷開,這個時間是由引數 wait_timeout
控制的,預設值是 28800 秒(也就是 8 小時)。你可以通過 show global variables
命令檢視這個配置值:
你可以通過 MySQL 配置檔案修改這個預設配置(mysqld
分組下配置即可)。
如果連線被斷開之後,客戶端再次傳送請求的話,就會收到一個錯誤提醒:Lost connection to MySQL server during query
。
長連線與短連線
在 MySQL 資料庫中,還有長連線與短連線的概念:
- 長連線是指連線成功後,如果客戶端持續有請求,則一直使用同一個連線,對應在 Web 應用中,就是後端程式與資料庫之間的連線建立之後,就會一直重用這個連線(為了提升資料庫併發性,可以建立一個數據庫連線池);
- 短連線則是指每次執行完很少的幾次查詢就斷開連線,下次查詢再重新建立一個,對應在 Web 應用中,就是後端程式與資料庫建立連線,完成查詢/更新後,就斷開連線,下次操作資料庫再重連。
這個和 HTTP 長連線和短連線的概念很像,並且顯然,無論是 HTTP 還是 MySQL,使用長連線都能有效減少建立連線過程帶來的損耗,進而提升效能。
不過在 MySQL 中,使用長連線會有一定的副作用 —— 有些時候會導致 MySQL 佔用記憶體漲得特別快。這是因為 MySQL 在執行過程中臨時使用的記憶體是管理在連線物件裡面的,這些資源只有在連線斷開的時候才會釋放。對於這個問題,通常有兩種解決方案:
- 定期斷開長連線:使用一段時間,或者程式裡判斷執行過一個佔用較大記憶體的查詢後,主動斷開連線;
- 如果使用的是 MySQL 5.7 或者更高版本,可以在每次執行一個比較大的操作後,通過執行
mysql_reset_connection
來重新初始化連線資源。
關於 MySQL 客戶端與服務端的連線,以及連線狀態和型別我們就簡單介紹到這裡,下篇教程,我們更進一步,來探究一條 SQL 查詢語句在 MySQL 客戶端和服務端之間都經歷了哪些曼妙之旅,最後把查詢結果返回給客戶端的。