MySQL道普請便り

第146回 Performance_schemaのエラー関連テーブル

この記事を読むのに必要な時間:およそ 4.5 分

概要

第16回 MySQLのエラーコードについてでは,MySQLのエラーをモニタリングすることの有用性を説明しています。

昔のMySQLはエラーはエラーログに出力されるかアプリケーション側に出力されるため,検知するための独自の仕組みを作ったりしていたかもしれません。最近のMySQLではPerformance_schemaを利用することで,MySQL単体でエラーをさまざまな角度で確認することができるようになっています。

今回は,そんなPerformance_schemaにあるエラー関連のテーブルを5つご紹介します。なお,今回利用している環境はCentOS 7で,MySQLのバージョンは8.0.23となります。

error_log

このテーブルはMySQLで起きたエラーログの内容が書き込まれます。カラムは上から時間(LOGGED⁠⁠,THREAD_ID,優先度(PRIO⁠⁠,エラーコード,サブシステム,データという構成になっています。優先度にはSystem,Error,Warning,Noteの4つが確認でき,通常のMySQLのエラーログと同じラベルが確認できます。

サブシステムはイベントが発生したサブシステムを確認するカラムで,ServerやInnoDB,Replなどの値が確認できます。たとえば,以下のエラーの場合semi-syncレプリケーションに関するエラーのため,サブシステムにはReplと表示されています。

mysql> SELECT * FROM performance_schema.error_log ORDER BY LOGGED DESC limit 1\G
*************************** 1. row ***************************
    LOGGED: 2021-04-23 14:19:15.873988
 THREAD_ID: 15
      PRIO: Warning
ERROR_CODE: MY-011153
 SUBSYSTEM: Repl
      DATA: Timeout waiting for reply of binlog (file: mysql-bin.000075, pos: 416), semi-sync up to file , position 0.
1 row in set (0.00 sec)

このテーブルは固定サイズのメモリを確保し,必要に応じて,古いイベントが自動的に削除されます。また,ステータス変数を確認することで以下のerror_logテーブルに関する以下の内容を確認することができます。

Error_log_buffered_bytes
現在利用しているerror_logテーブルのサイズ
Error_log_buffered_events
現在存在しているerror_logテーブルのイベントの数(error_logテーブルの件数)
Error_log_expired_events
領域を確保するために破棄されたイベントの数
Error_log_latest_write
最後に書き込まれたエラーログの時間
mysql> show status like 'Error_log%';
+---------------------------+------------------+
| Variable_name             | Value            |
+---------------------------+------------------+
| Error_log_buffered_bytes  | 117920           |
| Error_log_buffered_events | 681              |
| Error_log_expired_events  | 0                |
| Error_log_latest_write    | 1619155155873988 |
+---------------------------+------------------+
4 rows in set (0.00 sec)

このテーブルはSQLでエラーログを引くことができる点が魅力です。たとえば,制限などでSHELL操作ができない環境であったとしても,SQLが実行できればエラーログを確認することができます(※ただし,error_logテーブルへのSELECT権限は必要です⁠⁠。また,SQLを工夫することで,時間だけを取り出してエラーを確認したり,GROUP BYをつかうことで各エラーの件数を確認することができます。

mysql> SELECT RIGHT(logged,15),prio,error_code,subsystem,LEFT(data,22) FROM performance_schema.error_log ORDER BY LOGGED desc limit 3;
+------------------+---------+------------+-----------+------------------------+
| RIGHT(logged,15) | prio    | error_code | subsystem | LEFT(data,22)          |
+------------------+---------+------------+-----------+------------------------+
| 14:19:15.873988  | Warning | MY-011153  | Repl      | Timeout waiting for re |
| 00:41:39.522233  | System  | MY-010931  | Server    | /usr/local/mysql8023/b |
| 00:41:39.510540  | Warning | MY-010330  | Server    | 'tables_priv' entry 't |
+------------------+---------+------------+-----------+------------------------+
3 rows in set (0.01 sec)

events_errors_summary_by_account_by_error

このテーブルは,アカウントごとのエラーを確認することができます。特定のエラーに関してどのユーザーで起こったか確認したいときに,便利なテーブルになります。

SUM_ERROR_RAISEDカラムに,該当のエラーが発生した回数が記録されていきます。そのため,通常ざっとエラーを確認する際はWHERE句でSUM_ERROR_RAISED <> 0 などで条件を絞って確認してください。筆者の場合ですと,SQL_MODEを変更したいときに既存で実行されるSQLを探す際に,このテーブルを使ってワーニング状態で出力されるアカウントを特定していました。

また,SQLを書き換えたあとはLAST_SEENを確認することで,改修が完了しているか確認することもできました。

mysql> SELECT * FROM events_errors_summary_by_user_by_error where ERROR_NAME = 'WARN_DATA_TRUNCATED';
+------+--------------+---------------------+-----------+------------------+-------------------+---------------------+---------------------+
| USER | ERROR_NUMBER | ERROR_NAME          | SQL_STATE | SUM_ERROR_RAISED | SUM_ERROR_HANDLED | FIRST_SEEN          | LAST_SEEN           |
+------+--------------+---------------------+-----------+------------------+-------------------+---------------------+---------------------+
| NULL |         1265 | WARN_DATA_TRUNCATED | 01000     |                0 |                 0 | NULL                | NULL                |
| root |         1265 | WARN_DATA_TRUNCATED | 01000     |                1 |                 0 | 2020-04-10 13:12:30 | 2020-04-10 13:12:30 |
| repl |         1265 | WARN_DATA_TRUNCATED | 01000     |                0 |                 0 | NULL                | NULL                |
+------+--------------+---------------------+-----------+------------------+-------------------+---------------------+---------------------+
3 rows in set (0.02 sec)"

events_errors_summary_by_host_by_error

このテーブルは,HOSTごとに発生しているエラーを確認することができます。HOST単位でエラーを確認したいときに利用します。

mysql> SELECT * FROM events_errors_summary_by_host_by_error where ERROR_NAME = 'WARN_DATA_TRUNCATED';
+-----------+--------------+---------------------+-----------+------------------+-------------------+------------+-----------+
| HOST      | ERROR_NUMBER | ERROR_NAME          | SQL_STATE | SUM_ERROR_RAISED | SUM_ERROR_HANDLED | FIRST_SEEN | LAST_SEEN |
+-----------+--------------+---------------------+-----------+------------------+-------------------+------------+-----------+
| NULL      |         1265 | WARN_DATA_TRUNCATED | 01000     |                0 |                 0 | NULL       | NULL      |
| localhost |         1265 | WARN_DATA_TRUNCATED | 01000     |                0 |                 0 | NULL       | NULL      |
+-----------+--------------+---------------------+-----------+------------------+-------------------+------------+-----------+
2 rows in set (0.00 sec)

events_errors_summary_by_thread_by_error

このテーブルはTHREAD_ID単位で発生したエラーを確認することができます。Performance_schemaのevents_statements_historyのTHREAD_IDと組み合わせることで,エラーに該当SQLを特定できるか漏れしません。

ただし,events_statements_historyはテーブルがいっぱいになると古いものから削除されるため,必ず特定できるわけではありません。

mysql> SELECT * FROM events_errors_summary_by_thread_by_error WHERE SUM_ERROR_RAISED <> 0;
+-----------+--------------+---------------------------+-----------+------------------+-------------------+---------------------+---------------------+
| THREAD_ID | ERROR_NUMBER | ERROR_NAME                | SQL_STATE | SUM_ERROR_RAISED | SUM_ERROR_HANDLED | FIRST_SEEN          | LAST_SEEN           |
+-----------+--------------+---------------------------+-----------+------------------+-------------------+---------------------+---------------------+
|        68 |         3554 | ER_NO_SYSTEM_TABLE_ACCESS | HY000     |               12 |                 0 | 2021-04-29 11:50:22 | 2021-04-29 12:08:14 |
+-----------+--------------+---------------------------+-----------+------------------+-------------------+---------------------+---------------------+
1 row in set (0.06 sec)

events_errors_summary_global_by_error

このテーブルは発生したエラーの内容と件数を発生時間等を確認することができます。上の3つテーブルと違って,全体をサマリーした内容になっています。

mysql> SELECT * FROM events_errors_summary_global_by_error WHERE SUM_ERROR_RAISED <> 0 limit 3;
+--------------+---------------------------------+-----------+------------------+-------------------+---------------------+---------------------+
| ERROR_NUMBER | ERROR_NAME                      | SQL_STATE | SUM_ERROR_RAISED | SUM_ERROR_HANDLED | FIRST_SEEN          | LAST_SEEN           |
+--------------+---------------------------------+-----------+------------------+-------------------+---------------------+---------------------+
|         1064 | ER_PARSE_ERROR                  | 42000     |                4 |                 0 | 2021-03-16 00:42:14 | 2021-04-29 12:21:42 |
|         1774 | ER_MALFORMED_GTID_SPECIFICATION | HY000     |                2 |                 0 | 2021-04-23 14:17:02 | 2021-04-23 14:18:33 |
|         3554 | ER_NO_SYSTEM_TABLE_ACCESS       | HY000     |               52 |                 0 | 2021-04-27 05:47:48 | 2021-04-29 12:26:13 |
+--------------+---------------------------------+-----------+------------------+-------------------+---------------------+---------------------+
3 rows in set (0.01 sec)

まとめ

今回はMySQLのPerformance_schemaのエラーに関するテーブルを5つ紹介しました。エラーログだけでなく,Performance_schemaを利用することで,さまざまな角度でエラーを確認できることができます。

ヘルスチェックであったり,エラー調査の際には,ぜひこれらのテーブルを利用してみてください。

著者プロフィール

深町日出海(ふかまちひでみ)

GMOメディア株式会社のデータベースエンジニア。主にOracleとMySQLを担当。得意なプログラム言語はJava。MySQLの好きなところはTABLEやINDEXの識別子に64byteまで使えるところ。

Twitter:@lhfukamachi