1. 程式人生 > MYSQL進階教學 ><p>常見的 MySQL 異常及處理方法</p>

<p>常見的 MySQL 異常及處理方法</p>

在使用 MySQL 的過程中,我們會碰到各種各樣的問題,如資料庫突然響應很慢、表碎片空間佔比過大等。本小節我們一起來學習一些常見的 MySQL 異常,以及響應的處理方法。

1. 主從同步資料異常,如何跳過錯誤?

由於種種原因,有時候從庫可能會出現因主從資料導致的無法執行的 SQL 語句,那麼此時就要跳過該SQL 語句了。

1.1 binlog+position 模式

-- 在從庫上操作
1) 跳過錯誤報錯
mysql> stop slave;
mysql> set global sql_slave_skip_counter =1;
mysql> start slave;

2
) 檢視同步狀態 mysql> show slave status\G

1.2 GTID 模式

  • 方法一:直接跳過錯誤:
-- 在從庫上操作
1) 停止slave程序
mysql> STOP SLAVE;

2) 設定事務號,事務號從Executed_Gtid_Set獲取,在session裡設定gtid_next,即跳過這個GTID
如從show slave status拿到Executed_Gtid_Set為xxxx:1-4
mysql> SET @@SESSION.GTID_NEXT= 'xxxx:5'

3) 設定空事物
mysql> BEGIN; COMMIT
; 4) 恢復事物號 mysql> SET SESSION GTID_NEXT = AUTOMATIC; 5) 啟動slave程序 mysql> START SLAVE;
  • 方法二:重置master方法跳過錯誤
-- 在從庫上操作
-- 如從show slave status拿到Executed_Gtid_Set為xxxx:1-4,以下命令表示,忽略xxxx:1-5這個GTID事務,下一次事務接著從 6 這個GTID開始,即可跳過上述錯誤。
1) 停止slave程序
mysql> STOP SLAVE;

2) 重置MASTER
mysql> RESET MASTER;
3) 設定GTID_PURGED mysql> SET @@GLOBAL.GTID_PURGED ='xxxx:1-5'; 4) 啟動slave程序 mysql> START SLAVE;

2. 如何清理表碎片

當某張表刪除完大量資料,或 MySQL 執行很長時間(一般指半年)後,難免會產生表碎片,這時就要對錶進行碎片清理。

1) 查詢表碎片大小(一般碎片率超過30%,可以考慮清理表碎片)
mysql> select t.table_name, t.table_schema, t.ENGINE, t.TABLE_ROWS, ROUND(t.DATA_LENGTH/1024/1024,2) DATA_LENGTH_MB, ROUND(t.INDEX_LENGTH/1024/1024,2) INDEX_LENGTH_MB,
  ROUND((t.DATA_LENGTH+t.INDEX_LENGTH)/1024/1024,2) SUM_LENGTH_MB, ROUND(t.DATA_FREE/1024/1024,2) DATA_FREE_MB, CONCAT(ROUND((t.DATA_FREE / (t.DATA_LENGTH + t.INDEX_LENGTH + t.DATA_FREE)) * 100,2),'%') FRAGMENT_RATE 
  from information_schema.tables t
where 1=1
and t.DATA_FREE != 0
and (t.DATA_FREE / (t.DATA_LENGTH + t.INDEX_LENGTH + t.DATA_FREE)) >= 0.3 -- 碎片率超過30%
and t.TABLE_ROWS >= 0
and ROUND(t.DATA_FREE/1024/1024,2) >= 100
order by t.DATA_FREE / t.DATA_LENGTH desc

2) 清理表碎片
-- MyISAM儲存引擎
mysql> OPTIMIZE TABLE tbl_name

-- Innodb儲存引擎
mysql> ALTER TABLE tbl_name ENGINE = Innodb;

3. CPU突然爆表,如何解決?

CPU 使用率突然暴增至 90% 以上,資料庫響應非常緩慢,一般都是某個 SQL 出現效能問題,耗光 CPU 資源。

1) 定位問題sql
-- 找到執行時間很長,且佔用會話比較多的sql
mysql> show processlist\G
mysql> select * from information_schema.processlist order by info desc\G

2) 分析執行計劃,判斷sql是否存在優化空間
mysql> explain select * from xxx where xxx=xxx\G

3) 實施優化措施
這裡就比較考驗優化功力了,根據不同的問題sql,快速判斷需要採取何種優化措施。最簡單的例子,sql的where條件沒有走索引,而且欄位的選擇性比較高,那這時就要考慮給欄位建立相應的索引來解決。

4. 如何處理鎖表問題?

當發生死鎖問題時,一般通過 imformation_schema 的表來查詢相關的事務和鎖資訊,找到產生死鎖的源頭會話,將該會話kill掉。

1) 查詢產生死鎖的源頭會話
--以下sql能看到誰阻塞和誰在等待,以及等待多久的查詢。
mysql> SELECT
     IFNULL(wt.trx_mysql_thread_id, 1) BLOCKING_THREAD_ID,t.trx_mysql_thread_id WAITING_THREAD_ID, CONCAT(p. USER, '@', p. HOST) USER,
     p.info SQL_TEXT, l.lock_table LOCK_TABLE, l.lock_index LOCKED_INDEX, l.lock_type LOCK_TYPE, l.lock_mode LOCK_MODE,
     CONCAT(FLOOR(HOUR (TIMEDIFF(now(), t.trx_wait_started)) / 24),'day ',MOD (HOUR (TIMEDIFF(now(), t.trx_wait_started)),24),':',
     MINUTE (TIMEDIFF(now(), t.trx_wait_started)),':',SECOND (TIMEDIFF(now(), t.trx_wait_started))) AS WAIT_TIME,
     t.trx_started TRX_STARTED, t.trx_isolation_level TRX_ISOLATION_LEVEL, t.trx_rows_locked TRX_ROWS_LOCKED, t.trx_rows_modified TRX_ROWS_MODIFIED
     FROM INFORMATION_SCHEMA.INNODB_TRX t
     LEFT JOIN information_schema.innodb_lock_waits w ON t.trx_id = w.requesting_trx_id
     LEFT JOIN information_schema.innodb_trx wt ON wt.trx_id = w.blocking_trx_id
     INNER JOIN information_schema.innodb_locks l ON l.lock_trx_id = t.trx_id
     INNER JOIN information_schema. PROCESSLIST p ON t.trx_mysql_thread_id = p.id
     ORDER BY 1\G

5. 小結

本小節主要總結了一些經常碰到的 MySQL 異常及相應處理方法,除此之外,在實際使用過程當中,大家肯定還會碰到各種各樣的疑難雜症,經常進行總結可以積累豐富的實戰經驗。