Home
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try a Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

4

Local AI

--

Uedu Code

--

Taipei AQI 57 · Taichung AQI 74 · Tainan AQI 63 · Kaohsiung AQI 64
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 12

設定 MySQL

設定檔 my.cnf、系統變數與 SET PERSIST
Interaction實作導覽 20 minute(s)

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. 1

    確認 mysqld 會讀哪些設定檔

    投影片的 mysqld --verbose --help 會列出 mysqld 支援的所有選項(數百行),以及它依序讀取的設定檔。用 grep 只看設定檔那一段。後面讀到的檔案會覆蓋前面的設定。

  2. 2

    看目前的伺服器設定

    mysqld.cnf 大部分是註解。用 grep -Ev 濾掉註解與空行,只看實際生效的選項。Ubuntu 預設把 bind-address 設成 127.0.0.1:只有這台主機上的程式能連到 MySQL。

  3. 3

    先備份,再編輯

    改設定檔之前先複製一份,改壞了可以還原。用 nano 編輯,在 [mysqld] 區段的最後加上下面幾行,按 Ctrl+O 存檔、Ctrl+X 離開。1G 是示意值,請依主機的記憶體決定。

  4. 4

    重新啟動服務

    設定檔只在啟動時讀取,所以要重新啟動。Ubuntu 上 MySQL 服務的名稱是 mysql。重新啟動期間所有連線都會中斷,正式環境要挑沒有人使用的時段。Windows 則在「服務」(services.msc)重新啟動 MySQL80,或以系統管理員身分執行 net stop MySQL80 與 net start MySQL80。

  5. 5

    確認設定生效

    Ubuntu 的 root 預設用 auth_socket 驗證,以 sudo mysql 登入,不需要密碼。-e 直接執行一個 SQL 敘述就離開。

  6. 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 本身就擁有修改全域變數的權限。)

想一想:查看與修改系統變數

1.

模擬環境中,下面的查詢結果是什麼?

SELECT @@innodb_buffer_pool_size / 1024 / 1024;

(innodb_buffer_pool_size 是預設值 134217728)

2.

在真實的 MySQL 8.0 執行下面的敘述,結果是什麼?

SET max_connections = 300;
3.

你連上 MySQL 後執行 SET GLOBAL long_query_time = 2;(原本是 10),接著在同一條連線執行 SELECT @@long_query_time;,真實 MySQL 會顯示什麼?

第 1 次作答

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. 1

    設定並查看保存的內容

    performance_schema.persisted_variables 是 mysqld-auto.cnf 的 SQL 介面,列出保存的變數。

  2. 2

    重新啟動後再查一次

    設定檔 mysqld.cnf 裡寫的是 300(上一個導覽加的),但 mysqld-auto.cnf 最後讀取,所以重新啟動後的值是 500。同樣的情況如果用的是 SET GLOBAL,重新啟動後會變回設定檔的 300。

  3. 3

    取消保存的設定

    RESET PERSIST 只把這一項從 mysqld-auto.cnf 移除,目前執行中的值仍是 500;下次重新啟動才會回到設定檔的 300。

這段導覽完成了

想一想:設定會保留多久

1.

mysqld.cnf 沒有設定 max_connections(預設 151)。管理員執行 SET GLOBAL max_connections = 300; 之後,MySQL 重新啟動,max_connections 是多少?

2.

back_log(連線尖峰時,可以排隊等待處理的連線數)是唯讀變數,只能在啟動時設定。想把它改成 100,但手邊不方便編輯設定檔,在 SQL 裡要用哪一個敘述?

3.

把投影片的這行設定照抄進 MySQL 8.0 的 mysqld.cnf,會發生什麼事?

[mysqld]
set-variable = innodb_buffer_pool_size=70M
第 1 次作答

動手寫:暫時調高連線數上限

網站今天有活動,需要暫時把連線數上限調高到 200(活動結束、重新啟動後恢復原狀即可)。請:

  1. 用適當的 SET 敘述把 max_connections 改成 200
  2. 用一個 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。

這一課完成了!
Next lesson:管理資料庫
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。