Learning Objectives
- 找到 MySQL 的設定檔:Ubuntu 的 /etc/mysql/mysql.conf.d/mysqld.cnf、Windows 的 my.ini,看懂 [mysqld] 與 [client] 區段
- 說出常見選項的用途:port、bind-address、datadir、innodb_buffer_pool_size、max_connections、日誌與字元集
- 修改設定檔後重新啟動服務,並用 SHOW VARIABLES、SELECT @@變數 確認設定生效
- 分辨 GLOBAL 與 SESSION 兩種範圍,以及 SET GLOBAL、SET SESSION、SET PERSIST 的差別
- 把投影片的 MySQL 5 選項改寫成 MySQL 8.0 的寫法
預設值不一定適合你的伺服器
MySQL 安裝完就能使用,但它的預設值是為了「在任何電腦上都跑得起來」而設計的,例如:
- InnoDB 用來快取資料與索引的記憶體(buffer pool)預設只有 128 MB,伺服器有 32 GB 記憶體也只用這麼多
- 同時連線數上限預設 151,網站流量大時可能不夠
- 慢查詢紀錄(slow query log)預設關閉,查詢變慢時找不到原因
調整這些行為有兩個地方:
| 方式 | 何時生效 | 重新啟動後 |
|---|---|---|
| 設定檔(option file) | MySQL 啟動時讀取 | 保留 |
系統變數(SET GLOBAL 等) |
執行中立即修改,不必重啟 | SET GLOBAL 會消失,SET PERSIST 會保留 |
設定檔裡的每個選項,大多對應一個同名的系統變數:設定檔寫 max_connections = 300,啟動後 @@max_connections 就是 300。
本課先看設定檔,再看如何在 SQL 裡查詢與修改系統變數。
設定檔在哪裡、長什麼樣子
本課以 Ubuntu 24.04 用 apt install mysql-server 安裝的 MySQL 8.0 為準:
| 檔案 | 用途 |
|---|---|
/etc/mysql/my.cnf |
進入點,內容只有兩行 !includedir,把下面兩個資料夾裡的 .cnf 檔都讀進來 |
/etc/mysql/mysql.conf.d/mysqld.cnf |
伺服器 mysqld 的設定,主要修改這個檔案 |
/etc/mysql/conf.d/mysql.cnf |
命令列工具 mysql 的設定 |
~/.my.cnf |
個人的設定檔,放在使用者的家目錄 |
Windows 用 MySQL Installer 安裝時,設定檔是 C:\ProgramData\MySQL\MySQL Server 8.0\my.ini(ProgramData 是隱藏資料夾)。
投影片使用的 XAMPP 是把 MySQL(新版是 MariaDB)和網頁伺服器包在一起的教學套件,設定檔在 C:\xampp\mysql\bin\my.ini,正式伺服器不會這樣安裝。
設定檔的格式:
# 井字號開頭是註解
[mysqld] # 區段:下面的選項給伺服器程式 mysqld
port = 3306
bind-address = 127.0.0.1
max_connections = 300
innodb_buffer_pool_size = 1G
[client] # 區段:給所有用戶端程式(mysql、mysqldump…)
default-character-set = utf8mb4
[mysqld]是伺服器的設定,[client]是所有用戶端程式共用的設定,[mysql]只給mysql命令列工具- 選項名稱中的
-和_可以互換:bind-address與bind_address相同 - 大小可以加單位
K、M、G;開關可以寫1/0或ON/OFF - 設定檔只在 MySQL 啟動時讀取,修改後要重新啟動服務才會生效
常見的伺服器選項
| 選項 | 作用 | 8.0 的預設值 |
|---|---|---|
port |
監聽的連接埠 | 3306 |
bind-address |
接受哪個網路介面的連線;127.0.0.1 只接受本機 |
程式預設 *(所有介面),Ubuntu 的 mysqld.cnf 改成 127.0.0.1 |
datadir |
資料檔存放的資料夾 | Ubuntu 為 /var/lib/mysql |
innodb_buffer_pool_size |
InnoDB 快取資料與索引的記憶體 | 128M |
max_connections |
同時連線數上限 | 151 |
log_bin |
二進位日誌(記錄所有修改,用於備份還原與複寫) | 開啟(8.0 起預設開啟,要關閉寫 skip-log-bin) |
slow_query_log、slow_query_log_file |
慢查詢紀錄的開關與檔案位置 | 關閉 |
long_query_time |
執行超過幾秒算慢查詢 | 10 |
default_storage_engine |
建立表格沒有寫 ENGINE 時用的儲存引擎 | InnoDB |
character-set-server、collation-server |
伺服器預設的字元集與定序 | utf8mb4、utf8mb4_0900_ai_ci |
innodb_buffer_pool_size 是影響效能最大的選項。官方文件建議,專用的資料庫伺服器可以設到實體記憶體的 80% 左右;
和網頁伺服器、其他程式共用一台主機時要保守,留記憶體給其他程式。
投影片的選項在 MySQL 8.0 的寫法:
| 投影片(MySQL 4/5) | MySQL 8.0 |
|---|---|
set-variable = innodb_buffer_pool_size=70M |
innodb_buffer_pool_size = 70M(set-variable = 語法已移除) |
log-slow-queries |
slow_query_log = 1,檔案位置用 slow_query_log_file 指定 |
log-bin(要手動開啟) |
預設已開啟 |
innodb_additional_mem_pool_size = 10M |
已移除(5.7.4),不要再寫,否則 MySQL 無法啟動 |
innodb_log_file_size = 20M |
8.0.30 起改用 innodb_redo_log_capacity(預設 100 MB) |
innodb_data_file_path = ibdata1:10M:autoextend |
預設 ibdata1:12M:autoextend;而且 innodb_file_per_table 預設開啟,每張表格有自己的 .ibd 檔,很少需要調整 |
導覽:修改設定檔並重新啟動 MySQL
以下在 Ubuntu 伺服器上操作(提示字元 ubuntu@db-01:~$)。輸出只節錄重點,「…」代表省略的內容;時間、PID 等數字是示意值。
-
1
確認 mysqld 會讀哪些設定檔
投影片的
mysqld --verbose --help會列出 mysqld 支援的所有選項(數百行),以及它依序讀取的設定檔。用grep只看設定檔那一段。後面讀到的檔案會覆蓋前面的設定。 -
2
看目前的伺服器設定
mysqld.cnf大部分是註解。用grep -Ev濾掉註解與空行,只看實際生效的選項。Ubuntu 預設把bind-address設成127.0.0.1:只有這台主機上的程式能連到 MySQL。 -
3
先備份,再編輯
改設定檔之前先複製一份,改壞了可以還原。用
nano編輯,在[mysqld]區段的最後加上下面幾行,按 Ctrl+O 存檔、Ctrl+X 離開。1G是示意值,請依主機的記憶體決定。 -
4
重新啟動服務
設定檔只在啟動時讀取,所以要重新啟動。Ubuntu 上 MySQL 服務的名稱是
mysql。重新啟動期間所有連線都會中斷,正式環境要挑沒有人使用的時段。Windows 則在「服務」(services.msc)重新啟動 MySQL80,或以系統管理員身分執行net stop MySQL80與net start MySQL80。 -
5
確認設定生效
Ubuntu 的 root 預設用
auth_socket驗證,以sudo mysql登入,不需要密碼。-e直接執行一個 SQL 敘述就離開。 -
6
打錯字時 MySQL 會啟動失敗
設定檔有不認識的選項,MySQL 會拒絕啟動,而不是忽略它。啟動失敗時看錯誤日誌,找到問題那一行修正,再重新啟動。這也是先備份的原因:真的找不到問題,可以先
sudo cp ~/mysqld.cnf.bak /etc/mysql/mysql.conf.d/mysqld.cnf還原,讓服務恢復。
在 SQL 裡查看系統變數
連進 MySQL 之後,用兩種方式查看系統變數:
SHOW VARIABLES LIKE 'max_connections'; -- 名稱可以用 % 萬用字元,例如 'innodb_buffer_pool%'
SELECT @@max_connections; -- 取出一個變數的值,可以拿來計算
SHOW VARIABLES 適合「找」變數:不記得完整名稱時,用 LIKE '%log%' 搜尋。SELECT @@變數 適合「用」變數:
例如把位元組換算成 MB。設定檔的 bind-address 在系統變數裡寫成 bind_address(底線)。
本課的範例在 CodeLab 的模擬 MySQL 裡執行,變數值是模擬的預設值,只收錄常用的系統變數(真實的 MySQL 8.0 有六百多個); 你自己的伺服器數值會依安裝方式與設定不同。
查看伺服器目前的設定
這幾個查詢是接手一台陌生的 MySQL 時,常先做的檢查:連線數上限、buffer pool 多大、聽哪個連接埠、資料放在哪裡。(變數值是模擬環境的預設值。)
GLOBAL 與 SESSION:改全部還是只改自己
系統變數有兩種範圍:
- GLOBAL(全域):整個伺服器的值。新的連線建立時,會從 GLOBAL 複製一份成為自己的 SESSION 值
- SESSION(工作階段):只屬於目前這條連線的值,連線結束就消失,不影響別人
SET GLOBAL max_connections = 300; -- 改全域值,需要 SYSTEM_VARIABLES_ADMIN(或舊的 SUPER)權限
SET SESSION sql_mode = 'STRICT_TRANS_TABLES'; -- 只改自己這條連線;SESSION 可以省略
SELECT @@GLOBAL.sql_mode, @@SESSION.sql_mode; -- 分別取出兩種範圍的值;只寫 @@sql_mode 是 SESSION 值
SET GLOBAL max_connections = DEFAULT; -- 改回預設值
變數不一定兩種範圍都有,也不一定能在執行中修改。下面是在本機真實 MySQL 8.0.44 執行的結果:
mysql> SET SESSION max_connections = 300;
ERROR 1229 (HY000): Variable 'max_connections' is a GLOBAL variable and should be set with SET GLOBAL
mysql> SELECT @@SESSION.max_connections;
ERROR 1238 (HY000): Variable 'max_connections' is a GLOBAL variable
mysql> SET GLOBAL datadir = '/tmp';
ERROR 1238 (HY000): Variable 'datadir' is a read only variable
max_connections只有 GLOBAL:連線數上限是整台伺服器的事,沒有「我自己的連線數上限」datadir、port、bind_address是唯讀變數:只能寫在設定檔,重新啟動才會改變sql_mode、long_query_time兩種範圍都有
SET GLOBAL 不會改變已經連線者的 SESSION 值,包括你自己這條連線。 例如執行 SET GLOBAL long_query_time = 2 之後,
SELECT @@SESSION.long_query_time 仍然是 10,要重新連線才會拿到 2。
下面的範例用「另一個帳號重新連線」,觀察新連線拿到的是新的 GLOBAL 值。
SET GLOBAL 與 SET SESSION 影響的範圍
執行前已經建立帳號 fred。root 先改了一個 GLOBAL 值和一個 SESSION 值,接著 fred 開一條新的連線,看看他拿到的是什麼。(模擬環境中 root 本身就擁有修改全域變數的權限。)
想一想:查看與修改系統變數
模擬環境中,下面的查詢結果是什麼?
SELECT @@innodb_buffer_pool_size / 1024 / 1024;
(innodb_buffer_pool_size 是預設值 134217728)
在真實的 MySQL 8.0 執行下面的敘述,結果是什麼?
SET max_connections = 300;
你連上 MySQL 後執行 SET GLOBAL long_query_time = 2;(原本是 10),接著在同一條連線執行 SELECT @@long_query_time;,真實 MySQL 會顯示什麼?
SET PERSIST:修改並保留到下次啟動
SET GLOBAL 立即生效,但只存在記憶體裡,MySQL 重新啟動就恢復成設定檔的值。以前要讓修改永久有效,得同時改設定檔,兩邊很容易不一致。
MySQL 8.0 新增了 SET PERSIST:
SET PERSIST max_connections = 500; -- 像 SET GLOBAL 一樣立即生效,同時寫進 mysqld-auto.cnf
SET PERSIST_ONLY back_log = 100; -- 只寫進 mysqld-auto.cnf,下次啟動才生效(用於唯讀變數)
RESET PERSIST max_connections; -- 從 mysqld-auto.cnf 移除這一項(目前的值不變)
SELECT * FROM performance_schema.persisted_variables; -- 查看保存了哪些設定
mysqld-auto.cnf 是 MySQL 自己管理的 JSON 檔案,放在資料目錄(Ubuntu 是 /var/lib/mysql/mysqld-auto.cnf),
記錄每個變數的值、由哪個帳號在什麼時間設定。MySQL 啟動時最後讀它,所以它的值會蓋過 mysqld.cnf。
不要手動編輯這個檔案,用 SET PERSIST、RESET PERSIST 管理。
| 方式 | 立即生效 | 重新啟動後 | 適合 |
|---|---|---|---|
| 改設定檔 | 否,要重新啟動 | 保留 | 安裝時的基本設定、唯讀變數 |
SET GLOBAL |
是(新連線) | 消失 | 暫時調整、試驗 |
SET PERSIST |
是(新連線) | 保留 | 確定要長期使用的調整 |
SET PERSIST_ONLY |
否 | 保留 | 只能在啟動時設定的唯讀變數 |
SET SESSION |
是(只有自己) | 連線結束就消失 | 個別程式需要的設定,例如 sql_mode |
要查某個設定「到底從哪裡來」,performance_schema.variables_info 的 VARIABLE_SOURCE 欄位會顯示
COMPILED(程式預設)、GLOBAL(設定檔)、PERSISTED(mysqld-auto.cnf)或 DYNAMIC(執行中用 SET 修改)。
SET PERSIST 立即生效
SET PERSIST 的效果在執行當下和 SET GLOBAL 相同。寫進檔案、重新啟動後仍然存在這部分,模擬環境沒有檔案系統與重新啟動,請看下一個導覽。
導覽:重新啟動後,PERSIST 的設定還在
在 Ubuntu 伺服器上操作,接續上一個範例。時間等數字是示意值。
-
1
設定並查看保存的內容
performance_schema.persisted_variables是 mysqld-auto.cnf 的 SQL 介面,列出保存的變數。 -
2
重新啟動後再查一次
設定檔 mysqld.cnf 裡寫的是 300(上一個導覽加的),但 mysqld-auto.cnf 最後讀取,所以重新啟動後的值是 500。同樣的情況如果用的是
SET GLOBAL,重新啟動後會變回設定檔的 300。 -
3
取消保存的設定
RESET PERSIST只把這一項從 mysqld-auto.cnf 移除,目前執行中的值仍是 500;下次重新啟動才會回到設定檔的 300。
想一想:設定會保留多久
mysqld.cnf 沒有設定 max_connections(預設 151)。管理員執行 SET GLOBAL max_connections = 300; 之後,MySQL 重新啟動,max_connections 是多少?
back_log(連線尖峰時,可以排隊等待處理的連線數)是唯讀變數,只能在啟動時設定。想把它改成 100,但手邊不方便編輯設定檔,在 SQL 裡要用哪一個敘述?
把投影片的這行設定照抄進 MySQL 8.0 的 mysqld.cnf,會發生什麼事?
[mysqld]
set-variable = innodb_buffer_pool_size=70M
動手寫:暫時調高連線數上限
網站今天有活動,需要暫時把連線數上限調高到 200(活動結束、重新啟動後恢復原狀即可)。請:
- 用適當的 SET 敘述把
max_connections改成 200 - 用一個 SELECT 列出兩個欄位:全域的
max_connections(欄位名稱max_conn),以及innodb_buffer_pool_size換算成 MB 的值(欄位名稱buffer_pool_mb,除以 1024 再除以 1024)
重點整理
| 項目 | 重點 |
|---|---|
| Ubuntu 設定檔 | /etc/mysql/mysql.conf.d/mysqld.cnf,[mysqld] 區段 |
| Windows 設定檔 | C:\ProgramData\MySQL\MySQL Server 8.0\my.ini |
| 生效時機 | 設定檔只在啟動時讀取:sudo systemctl restart mysql |
| 查看 | SHOW VARIABLES LIKE '…'、SELECT @@變數、@@GLOBAL./@@SESSION. |
| 暫時修改 | SET GLOBAL(新連線生效,重啟消失)、SET SESSION(只有自己) |
| 保存修改 | SET PERSIST(寫進資料目錄的 mysqld-auto.cnf)、RESET PERSIST 取消 |
- 改設定檔前先備份;選項打錯字 MySQL 會拒絕啟動,看
/var/log/mysql/error.log - 唯讀變數(
datadir、port、bind_address)只能寫在設定檔或用SET PERSIST_ONLY,重新啟動才生效 - 投影片的
set-variable =、log-slow-queries、innodb_additional_mem_pool_size在 8.0 都已移除
下一課介紹日常管理用的 SHOW 指令、伺服器狀態與 mysqladmin。