目錄
一、前置知識點
MySQL的運行原理
1.?客戶端連接
2.?SQL 解析與優化
3.?存儲引擎處理
4.?日志與持久化
二、MySQL 單實例故障排查
(1)故障現象1
(2)故障現象2
(3)故障現象3
(4)故障現象4
(5)故障現象5
(6)故障現象6
(7)故障現象7
(8)故障現象8
三、MySQL 主從故障排查
(1)故障現象1
(2)故障現象2
(3)故障現象3
四、MySQL 優化
1、硬件方面
(1)關于 CPU
(2)關于內存
(3)關于磁盤
2、MySQL 配置文件
(1)核心功能優化項
(2)查詢優化項
(3)日志與監控
(4)InnoDB 高級優化
(5)示例配置(my.cnf)
3、SQL 方面
(1)創建測試表并插入數據
(2)使用 EXPLAIN 進行 SQL 優化的步驟及實驗驗證
(3)優化步驟:添加索引
(4)優化后查詢及 EXPLAIN 分析
一、前置知識點
MySQL的運行原理
1.?客戶端連接
-
客戶端通過 TCP/IP 或 Socket 連接到 MySQL 服務端。
-
連接管理器(Connection Manager)負責管理線程池和用戶認證。
2.?SQL 解析與優化
-
解析器:將 SQL 語句解析為語法樹,驗證語法合法性。
-
優化器:生成執行計劃,選擇索引或全表掃描等策略。
3.?存儲引擎處理
-
執行引擎:調用存儲引擎(如 InnoDB、MyISAM)執行讀寫操作。
-
數據存儲:
-
InnoDB:數據存儲在表空間文件(
.ibd
)中,支持事務和行級鎖。 -
MyISAM:數據存儲在?
.MYD
(數據文件)和?.MYI
(索引文件)中,不支持事務。
-
4.?日志與持久化
-
Redo Log(重做日志):確保事務的持久性,崩潰恢復時重放未提交的事務。
-
Undo Log(回滾日志):支持事務回滾和多版本并發控制(MVCC)。
-
Binlog(二進制日志):記錄所有數據變更,用于主從復制和增量備份。
二、MySQL 單實例故障排查
(1)故障現象1
ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/data/mysql/mysql.sock' (2)
問題分析:以上這種情況一般都是數據庫未啟動、mysql 配置文件未指定 socket 文件或者數據庫端口被防火墻攔截導致。
解決方法:啟動數據庫或者防火墻開放數據庫監聽端口。
(2)故障現象2
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)
問題分析:密碼不正確或者沒有權限訪問。
解決方法:
修改 my.cnf 主配置文件,在 [mysqld] 下添加 skip - grant - tables=on,重啟數據庫。最后修改密碼命令如下:
Mysql5.7 版本
mysql> update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost';
mysql> flush privileges;
Mysql8.0
mysql> UPDATE mysql.user SET authentication_string='' WHERE user='root' AND Host='localhost';
mysql> FLUSH PRIVILEGES;
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY '123456';
再刪除剛剛添加的 skip-grant-tables 參數,重啟數據庫,使用新密碼即可登錄。重新授權,命令如下。
Mysql5.7
mysql>grant all on *.* to 'root'@'mysql-server' identified by '123456';
Mysql8.0
mysql> CREATE USER 'root'@'mysql-server' IDENTIFIED BY '123456';
mysql> GRANT all ON *.* TO 'root'@'mysql-server';
(3)故障現象3
使用遠程連接數據庫時偶爾會發生遠程連接數據庫很慢的問題
問題分析:如果MySQL主機查詢DNS很慢或有很多客戶端連接導致很慢,由于開發機器是不可以連接外網的,在進行MySQL連接時,DNS解析是不可能完成的,從而也就明白了連接那么慢的原因。
解決方法:修改配置文件my.cnf ,在[mysql] 下添加 skip-name-resolve,重啟數據庫可以解決,注意在以后授權里面不能再使用主機名授權。
(4)故障現象4
Can’t open file: 'xxx_forums.MYI'. (errno: 145)
問題分析:服務器非正常關機,數據庫所在空間已滿,或一些其他未知原因,對數據庫表造成了損壞。可能是系統下直接將數據庫文件拷貝,會因為文件的屬組問題產生這個錯誤。
解決方法:
1.可以使用兩種方式修復數據表
- 使用 MySQL 自帶的專門用戶數據表檢查和修復工具 myisamchk。一般情況下只有在命令行下面才能運行 myisamchk 命令。常用的修復命令為:
myisamchk -r 數據文件目錄/數據表名.MYI;
- 通過 phpMyAdmin 修復,phpMyAdmin 帶有修復數據表的功能,進入到某一個表中后,點擊 “操作”,在下方的 “表維護” 中點擊 “修復表” 即可。
注意:以上兩種修復方式在執行前一定要備份數據庫。
- 修改文件的屬組(僅適合獨立主機用戶):
- 復制數據庫文件的過程中沒有將數據庫文件設置為 MySQL 運行的帳號可讀寫(一般適用于 Linux 和 FreeBSD 用戶)。
(5)故障現象5
ERROR 1129 (HY000): Host 'xxx.xxx.xxx' is blocked because of many connection erros;
unblock with 'mysqladmin flush-hosts'
問題分析:由于數據庫參數:max_connect_errors , 其默認值是10.當大量的主機去連接MySQL ,總連接請求超過了,新的連接就無法連上MySQL。同一個IP在短時間內產生太多中斷的數據庫連接而導致的阻塞。
解決方法:使用 mysqladmin flush-hosts 命令清除緩存
(6)故障現象6
客戶端報 Too many connections.
問題分析:連接數超出MySQL的最大連接數限制
解決方法:1.在 /etc/my.cnf 配置文件增大連接數,然后重啟MySQL
? ? ? ? ? ? ? ? ? ? ?max_connections = 10000
? ? ? ? ? ? ? ? ? ? 2.臨時修改最大連接數,在my.cnf 里修改
? ? ? ? ? ? ? ? ? ? ? set GLOBL max_connections = 10000
(7)故障現象7
Warning:World-writable config file '/etc/my.cnf' is ignored
ERROR! MySQL is running but PID file could not be found
問題分析:MySQL 的配置文件/etc/my.cnf 權限不對
解決方法:給它權限? chmod 644 /etc/my.cnf
(8)故障現象8
InnoDB: Error:page 14178 log sequence number 29455369832
InnoDB:is in the future!Current system log sequence number 29455369832f
問題分析: innodb 數據文件損壞。
解決方法:修改 my.cnf 配置文件,在[mysql] 下添加 innodb_force_recovery=4,啟動數據庫后備份數據文件,然后去掉該參數,利用備份文件恢復數據。
三、MySQL 主從故障排查
(1)故障現象1
從庫的 Slave_IO_Running 為 NO
The slave I/O thread stops because master and slave have equal MySQL server ids; these ids must be different for replication to work (or the --replicate-same-server-id option must be used on slave but this does not always make sense; please check the manual before using it).
問題分析:主庫和從庫的 server-id 值一樣。
解決方法:修改從庫的 server-id 的值,修改為和主庫不一樣。修改完后重啟,再同步即可。?
(2)故障現象2
從庫的 Slave_IO_Running 為 NO
問題分析:造成從庫線程為 NO 的原因會有很多,主要原因是主鍵沖突或者主庫刪除或更新數據,從庫找不到記錄,數據被修改導致。通常狀態碼報錯有 1007、1032、1062、1452 等。
解決方法一:
mysql> stop slave;
mysql> set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
mysql> start slave;
解決方法二:
設置用戶權限,設置從庫只讀權限
set global read_only=true;
(3)故障現象3
Error initializing relay log position: I/O error reading the header from the binary log
分析問題:從庫的中繼日志 relay-bin 損壞。
解決方法:手工修復,重新找到同步的 binlog 和 pos 點,然后重新同步即可。
mysql>CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.xxx', MASTER_LOG_POS=xxx;
四、MySQL 優化
1、硬件方面
(1)關于 CPU
優化目標:
-
提升并行處理能力,減少 SQL 執行和鎖競爭帶來的 CPU 瓶頸。
關鍵策略:
-
選擇多核 CPU:
-
MySQL 支持多線程操作(如并行查詢、連接處理),多核 CPU 能更好地處理高并發請求。
-
建議:優先選擇主頻高、核心數多的 CPU(如 16 核以上)。
-
-
監控 CPU 使用率:
# 查看 CPU 負載 top # 檢查用戶態(us)和內核態(sy)的 CPU 占用 vmstat 1
-
常見問題:
-
us
?高:SQL 執行消耗過多 CPU(需優化慢查詢)。 -
sy
?高:系統內核資源爭用(如鎖競爭、線程切換)。
-
-
-
優化鎖與并發:
-
減少表鎖(MyISAM)或行鎖(InnoDB)競爭:
-- 查看鎖等待 SHOW ENGINE INNODB STATUS\G -- 查看當前運行事務 SELECT * FROM information_schema.INNODB_TRX;
-
(2)關于內存
優化目標:
-
最大化利用內存緩存數據,減少磁盤 I/O。
關鍵策略:
-
配置 InnoDB 緩沖池:
-
innodb_buffer_pool_size
?是 InnoDB 引擎的核心參數,用于緩存數據和索引。 -
建議:設置為系統總內存的?70%~80%(需預留內存給操作系統和其他進程)。
# my.cnf 示例 innodb_buffer_pool_size = 64G
-
-
優化其他內存區域:
-
連接線程內存:
thread_cache_size = 100 # 緩存線程數 max_connections = 1000 # 最大連接數
-
排序和臨時表內存:
sort_buffer_size = 4M # 排序緩沖區 tmp_table_size = 256M # 內存臨時表大小
-
-
監控內存使用:
-- 查看 InnoDB 緩沖池命中率 SHOW STATUS LIKE 'Innodb_buffer_pool_read%'; -- 計算命中率公式: -- (1 - Innodb_buffer_
(3)關于磁盤
優化目標:
-
提升 I/O 吞吐量,降低數據讀寫延遲。
關鍵策略:
-
選擇高性能存儲設備:
-
SSD:比 HDD 快 10 倍以上,尤其適合隨機 I/O 密集場景。
-
RAID 配置:
-
RAID 10:兼顧性能與冗余,適合 OLTP 場景。
-
RAID 5:適合讀多寫少的 OLAP 場景。
-
-
-
分離日志與數據文件:
-
日志文件(binlog、redo log):
-
寫入頻繁且順序寫入,建議單獨掛載高速 SSD。
-
-
數據文件:
-
隨機讀寫較多,使用獨立磁盤或 RAID 10。
-
-
-
優化文件系統與 I/O 調度:
-
文件系統:使用 XFS 或 ext4(啟用?
noatime
?減少元數據寫入)。 -
I/O 調度器:
# 查看當前調度策略 cat /sys/block/sda/queue/scheduler # 設置為 deadline 或 noop(SSD 推薦) echo 'deadline' > /sys/block/sda/queue/scheduler
-
-
監控磁盤 I/O:
# 查看磁盤吞吐量和延遲 iostat -x 1 # 檢查 I/O 等待時間 top(關注 %wa 指標)
2、MySQL 配置文件
(1)核心功能優化項
參數 | 作用 | 建議配置 | 注意事項 |
---|---|---|---|
innodb_buffer_pool_size | InnoDB 緩沖池大小,緩存數據和索引,直接影響讀性能 | 設置為物理內存的 50%~70%(如 64GB 內存配 40G) | 避免超過物理內存,防止系統交換(Swap) |
innodb_log_file_size | 單個 InnoDB 重做日志文件大小,影響事務提交速度和崩潰恢復時間 | 建議 1G~4G(如 2G) | 修改需停止 MySQL,刪除舊日志文件后重啟 |
innodb_flush_log_at_trx_commit | 控制事務日志刷新策略,平衡性能與數據安全 | 1(默認,完全持久化);2(折中,每秒刷盤);0(高性能,風險高) | 高并發寫入場景可設為 2,但需容忍最多 1 秒數據丟失 |
max_connections | 最大客戶端連接數,避免連接耗盡 | 根據業務需求設置,建議 500~2000 | 監控 Threads_connected 和 Threads_running 調整 |
tmp_table_size、max_heap_table_size | 內存臨時表大小上限,影響復雜查詢(如 GROUP BY、JOIN) | 建議 64M~256M(如 128M),兩者值需一致 | 過小會導致磁盤臨時表,降低性能;過大可能耗盡內存 |
(2)查詢優化項
參數 | 作用 | 建議配置 |
---|---|---|
query_cache_type | 查詢緩存類型(MySQL 8.0 已移除,舊版本慎用) | OFF(默認,高并發下建議關閉) |
sort_buffer_size | 排序操作緩沖區大小 | 2M~8M(如 4M) |
join_buffer_size | JOIN 操作緩沖區大小 | 4M~16M(如 8M,僅對無索引 JOIN 有效) |
read_buffer_size | 順序讀緩沖區大小 | 2M~8M(如 4M) |
read_rnd_buffer_size | 隨機讀緩沖區大小 | 4M~16M(如 8M) |
(3)日志與監控
參數 | 作用 | 建議配置 |
---|---|---|
slow_query_log | 啟用慢查詢日志 | ON |
long_query_time | 定義慢查詢閾值(秒),記錄執行時間長的 SQL | 1~2(根據業務容忍度調整) |
log_error | 錯誤日志路徑,用于故障排查 | 指定路徑(如 /var/log/mysql/error.log ) |
binlog_format | 二進制日志格式(主從復制依賴) | ROW(推薦,數據一致性高) |
expire_logs_days | 自動清理舊的二進制日志天數 | 7~14(根據備份策略調整) |
(4)InnoDB 高級優化
參數 | 作用 | 建議配置 |
---|---|---|
innodb_io_capacity | InnoDB 后臺任務的 I/O 能力(如刷新臟頁) | SSD 建議 2000~4000,HDD 建議 200~400 |
innodb_flush_method | 控制數據文件與日志文件的刷新方式 | O_DIRECT(默認,避免雙緩沖) |
innodb_thread_concurrency | InnoDB 并發線程數(默認,自適應),高并發場景影響性能 | 可設為 CPU 核數 * 2 |
innodb_autoinc_lock_mode | 自增鎖模式,影響插入(連續模式,高并發插入性能) | 2 |
(5)示例配置(my.cnf)
物理資源 32 核 CPU、64G 內存、500G SSD
[mysqld]
# 核心配置
innodb_buffer_pool_size = 40G
innodb_log_file_size = 2G
innodb_flush_log_at_trx_commit = 2
max_connections = 1000
thread_cache_size = 100
# 查詢優化
tmp_table_size = 128M
max_heap_table_size = 128M
sort_buffer_size = 4M
join_buffer_size = 8M
# 日志與監控
slow_query_log = ON
long_query_time = 1
log_error = /var/log/mysql/error.log
binlog_format = ROW
expire_logs_days = 7
# InnoDB 高級
innodb_io_capacity = 2000
innodb_flush_method = O_DIRECT
innodb_thread_concurrency = 0
innodb_autoinc_lock_mode = 2
3、SQL 方面
SQL 優化是保障數據庫高效運行的關鍵,核心是減少 CPU、內存、磁盤 I/O 等資源消耗,提升查詢響應。未優化 SQL 在大數據量或高并發時會引發全表掃描等問題,致服務器負載高、響應慢,影響業務。可借助索引優化等手段降低數據庫壓力,支持業務擴展,控制成本與運維復雜度。
(1)創建測試表并插入數據
-- 創建數據庫
Create database test;
-- 使用數據庫
Use test;CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50) NOT NULL,email VARCHAR(100) NOT NULL,age INT NOT NULL,created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);--插入 10 萬條測試數據(使用存儲過程生成)
DELIMITER $$
CREATE PROCEDURE insert_users()
BEGINDECLARE i INT DEFAULT 0;WHILE i < 100000 DOINSERT INTO users (name, email, age)VALUES (CONCAT('user', i), CONCAT('user', i, '@example.com'), FLOOR(RAND() * 100));SET i = i + 1;END WHILE;
END$$
DELIMITER ;CALL insert_users();
(2)使用 EXPLAIN 進行 SQL 優化的步驟及實驗驗證
EXPLAIN 是 MySQL 分析 SQL 執行計劃的工具,模擬查詢執行輸出訪問類型、索引使用、掃描行數、額外操作等關鍵信息,能幫開發者找出全表掃描、索引失效等性能問題,進而從添加索引、改寫查詢、調整表結構等方面優化,是提升數據庫效率的重要診斷工具。
例如:
mysql>EXPLAIN SELECT * FROM users WHERE name = 'user123';
EXPLAIN 用于顯示 MySQL 如何執行一條 SQL 語句,關鍵字段如下:
字段 | 說明 | 優化關注點 |
---|---|---|
id | 查詢序列號,相同 id 為同一執行層,不同 id 按序執行(如查看復雜查詢的嵌套層級) | - |
select_type | 查詢類型(SIMPLE、PRIMARY、SUBQUERY、DERIVED 等) | 識別子查詢或臨時表操作 |
table | 訪問的表名或別名 | 確認查詢涉及的表 |
type | 訪問類型,性能從優到劣:system > const > eq_ref > ref > range > index > ALL | 避免 ALL(全表掃描),優先優化為 ref 或 range |
possible_keys | 可能使用的索引 | 檢查是否有合適索引未被使用 |
key | 實際使用的索引 | 確認是否命中最佳索引 |
rows | 預估掃描的行數 | 行數越少,查詢效率越高 |
Extra | 附加信息(如 Using where、Using index、Using temporary 等) | 發現潛在性能問題( |
根據關鍵字段說明,對 explain SELECT * FROM users WHERE name = 'user123' 的結果分析如下:
- type=ALL:全表掃描,效率極低。
- possible_keys=NULL:未命中索引。
- rows=100000:掃描全部數據。
(3)優化步驟:添加索引
mysql>ALTER TABLE users ADD INDEX idx_name (name);
(4)優化后查詢及 EXPLAIN 分析
mysql>EXPLAIN SELECT * FROM users WHERE name = 'user123';
?
優化后結果分析如下:
- type=ref:索引查找,效率高。
- key=idx_name:命中新創建的索引。
- rows=1:僅掃描一行數據。