この連載が書籍になりました!『MySQL 即効クエリチューニング

performance_schemaをsysで使い倒す!

2016年7月21日(木)
yoku0825

パフォーマンススキーマとは

「パフォーマンススキーマ」は、MySQL 5.5.3から導入されたパフォーマンスモニタリングのためのストレージエンジンです(第6回でも一部利用)。MySQL 5.5時代はローレベルな情報(mutex待ち、ロック待ち、I/O待ち)のみを提供し、通常運用に役に立つ情報はありませんでしたが、MySQL 5.6以降で大きく機能が追加され、十分クエリーチューニングに役立つ強力なツールに生まれ変わりました。

MySQL 5.6以降ではデフォルトでONに設定されるようになったパフォーマンススキーマですが、MySQL 5.5時代をご存知の方は明示的にOFFにしているかも知れません(MySQL 5.5のパフォーマンススキーマはパフォーマンスへのオーバーヘッドが非常に大きかった上に、大量にメモリーを利用した)。最近のパフォーマンススキーマはON/OFFに再起動が必要な点こそ変わりませんが、パフォーマンスオーバーヘッド、メモリー使用量ともに大幅に改善されています。また、取得できる情報も「ステートメント(ダイジェスト)単位での各種待ち状態の統計」、「各ステージでの経過時間」、「トランザクション単位での統計」などが追加され、さらに「スキーマ単位、テーブル単位で記録するか否か」、「ユーザー単位、ホスト単位で記録するか否か」を設定できるようになっています。

このような大幅な機能追加とオーバーヘッドの削減により、MySQL 5.6以降ではONにする価値は十分あるのではないでしょうか(筆者の会社の本番環境では、MySQL 5.6以降のパフォーマンススキーマは原則ONにしている)。

パフォーマンススキーマの設定

ややこしい話ですが、パフォーマンススキーマの機能はデータの格納/取り出しにPERFORMANCE_SCHEMAストレージエンジンを利用し、名前空間としてperformance_schemaデータベース(SHOW DATABASESを実行すると performance_schema が表示される)を利用します。また、パフォーマンススキーマを有効化するオプションはperformance_schemaです。なお、これらのパフォーマンススキーマ(機能)、performance_schemaデータベース、performance_schemaオプションはp_sと略されることが多いです(一般ユーザー同士でPERFORMANCE_SCHEMAストレージエンジンに言及する機会は少ない。PERFORMANCE_SCHEMAストレージエンジンを省略する場合は perfschemaが使われることが多い)。

以下で説明するコマンドの出力例などは全てMySQL 5.7.13のものです。原則、同様の手順でMySQL 5.6でも設定できますが、MySQL 5.7で新規に追加された機能があるため、一部MySQL 5.6では確認できないテーブルや行、カラムが存在します。気が付いたら「MySQL 5.7で追加されたんだな」と思ってください。

パフォーマンススキーマが有効かどうかは、performance_schema変数を参照することで確認できます。

mysql> SHOW VARIABLES LIKE 'performance_schema';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| performance_schema | ON    |
+--------------------+-------+
1 row in set (0.01 sec)

パフォーマンススキーマの設定に関するテーブルは、performance_schemaデータベースでsetup_の接頭辞を持つテーブルにまとめられています。

mysql> SHOW TABLES FROM performance_schema LIKE 'setup\_%';
+-----------------------------------------+
| Tables_in_performance_schema (setup\_%) |
+-----------------------------------------+
| setup_actors                            |
| setup_consumers                         |
| setup_instruments                       |
| setup_objects                           |
| setup_timers                            |
+-----------------------------------------+
5 rows in set (0.00 sec)

パフォーマンススキーマはSQLで設定します(起動時のみオプションでも設定可能。パフォーマンススキーマ起動構成を参照)。現在の設定を確認するにはSELECTステートメントを、設定を変更するにはUPDATE .. SET .. WHERE ..ステートメントを使用します。

setup_actors

パフォーマンススキーマによる統計の記録をユーザー単位、接続元ホスト単位で有効にするための設定ができます。デフォルトではHOST = '%', USER = '%', ENABLED = 'YES', HISTORY = 'YES'の行が設定されており、全ての接続元からの全てのユーザーが統計の取得対象になっています。この1行を削除し、HOST = '192.168.0.101', USER = '%', ENABLED = 'YES', HISTORY = 'YES'の行を追加すると、特定のホストからの接続のみを記録し、その他のホストからの接続はオーバーヘッドを削減する、といった使い方ができます(このテーブルの情報はMySQLを再起動すると消える(=デフォルトのHOST = '%', USER = '%', ENABLED = 'YES', HISTORY = 'YES' に戻る)。必要ならばinit_fileオプションでこのテーブルの設定をスタートアップ時に編集するようにしておくと良い)。

setup_actorsテーブルへの設定は、次回のコネクション確立時から有効になります。コネクションプールを利用している環境では注意してください(現在接続中のスレッド単位でパフォーマンススキーマの機能を有効/無効にするにはperformace_schema.threads テーブルを利用する)。

setup_consumers

setup_consumersテーブルでは、パフォーマンススキーマが計測した統計を記録するかどうかを設定します。

mysql> SELECT * FROM setup_consumers;
+----------------------------------+---------+
| NAME                             | ENABLED |
+----------------------------------+---------+
| events_stages_current            | NO      |
| events_stages_history            | NO      |
| events_stages_history_long       | NO      |
| events_statements_current        | YES     |
| events_statements_history        | YES     |
| events_statements_history_long   | NO      |
| events_transactions_current      | NO      |
| events_transactions_history      | NO      |
| events_transactions_history_long | NO      |
| events_waits_current             | NO      |
| events_waits_history             | NO      |
| events_waits_history_long        | NO      |
| global_instrumentation           | YES     |
| thread_instrumentation           | YES     |
| statements_digest                | YES     |
+----------------------------------+---------+
15 rows in set (0.00 sec)

MySQL 5.7.13現在、デフォルトは上記のようになっています。コンシューマーの名前(setup_consumers.nameの値)とperformance_schemaスキーマ内のテーブル名は大よそ紐づいているので、なんとなく何が有効/無効なのか(また、どこを有効にすると取得したい情報が取れるのか)がわかるかと思います。詳細はリファレンスマニュアルに記載があります。events_stages_*はプロファイラーとしての機能を(前回も利用)、events_statements_*はステートメント単位の統計情報を記録するための機能を、events_waits_*は非常にローレベルなmutexの競合やファイルシステムのsyncなど、MySQLが「待って」いた統計情報を記録するための機能を提供します。

これらがENABLED = NOになっていた場合、performance_schemaデータベース上にテーブルは残りますが、中身は記録されません(起動後にUPDATEステートメントでENABLED = NOにした場合、それ以降の統計情報が記録されなくなる)。

setup_instruments

setup_instrumentsテーブルには、setup_consumersテーブルよりさらに細分化された「パフォーマンススキーマがどのイベントの統計情報を記録するか」が設定されています。nameカラムの値はスラッシュで区切られた名前空間を持ちます。ざっくりとSQLでENABLED = YESになっている項目とENABLED = NOになっている項目の数を数えてみます。

mysql> SELECT SUBSTRING_INDEX(`name`, '/', 2) AS short_name, ANY_VALUE(name) AS example, SUM(ENABLED = 'YES') AS enabled, SUM(ENABLED = 'NO') AS disabled FROM setup_instruments GROUP BY short_name;
+---------------------------+-----------------------------------------------------+---------+----------+
| short_name                | example                                             | enabled | disabled |
+---------------------------+-----------------------------------------------------+---------+----------+
| idle                      | idle                                                |       1 |        0 |
| memory/archive            | memory/archive/FRM                                  |       0 |        2 |
| memory/blackhole          | memory/blackhole/blackhole_share                    |       0 |        1 |
| memory/client             | memory/client/mysql_options                         |       0 |        7 |
| memory/csv                | memory/csv/TINA_SHARE                               |       0 |        5 |
| memory/federated          | memory/federated/FEDERATED_SHARE                    |       0 |        1 |
| memory/innodb             | memory/innodb/adaptive hash index                   |       0 |       85 |
| memory/keyring            | memory/keyring/KEYRING                              |       0 |        1 |
| memory/memory             | memory/memory/HP_SHARE                              |       0 |        4 |
| memory/myisam             | memory/myisam/MYISAM_SHARE                          |       0 |       21 |
| memory/myisammrg          | memory/myisammrg/MYRG_INFO                          |       0 |        2 |
| memory/mysys              | memory/mysys/max_alloca                             |       0 |       21 |
| memory/partition          | memory/partition/ha_partition::file                 |       0 |        3 |
| memory/performance_schema | memory/performance_schema/mutex_instances           |      70 |        0 |
| memory/sql                | memory/sql/Locked_tables_list::m_locked_tables_root |       0 |      152 |
| memory/vio                | memory/vio/ssl_fd                                   |       0 |        3 |
| stage/innodb              | stage/innodb/alter table (end)                      |       8 |        0 |
| stage/mysys               | stage/mysys/Waiting for table level lock            |       0 |        1 |
| stage/sql                 | stage/sql/After create                              |       1 |      119 |
| statement/abstract        | statement/abstract/Query                            |       3 |        0 |
| statement/com             | statement/com/Sleep                                 |      32 |        0 |
| statement/scheduler       | statement/scheduler/event                           |       1 |        0 |
| statement/sp              | statement/sp/stmt                                   |      16 |        0 |
| statement/sql             | statement/sql/select                                |     141 |        0 |
| transaction               | transaction                                         |       0 |        1 |
| wait/io                   | wait/io/file/sql/map                                |      55 |        3 |
| wait/lock                 | wait/lock/table/sql/handler                         |       1 |        1 |
| wait/synch                | wait/synch/mutex/sql/TC_LOG_MMAP::LOCK_tc           |       0 |      257 |
+---------------------------+-----------------------------------------------------+---------+----------+
28 rows in set (0.01 sec)

例えば、25行目(下から3行目)を見るとname LIKE 'wait/io%'に属する項目は58あり、そのうちENABLED = YESは55項目、ENABLED = NOは3項目、そしてname LIKE 'wait/io%'に属する項目の1つの例としてwait/io/file/sql/mapがあるようだ、といったことを上記のSQLから見て取れます。

setup_instrumentsテーブルの設定とsetup_consumersテーブルの設定のうち、両方がENABLED = YESになっているものがパフォーマンススキーマで計測、蓄積されます(前回の記事を参照。setup_consumersテーブルのevents_stages_*setup_instrumentsテーブルのstage/sql/*を両方有効にしている)。改めての注意になりますが、performance_schemaデータベースで行った設定変更は、原則「即時」にサーバー「全体」へ反映されます。WHERE句なしでENABLED = YESにするのはステージング環境だけに留めておきましょう(設定項目によってはまだオーバーヘッドがある)。

setup_objects

setup_objectsテーブルは、オブジェクト単位でパフォーマンススキーマの有効/無効を設定できます。

mysql> SELECT * FROM setup_objects;
+-------------+--------------------+-------------+---------+-------+
| OBJECT_TYPE | OBJECT_SCHEMA      | OBJECT_NAME | ENABLED | TIMED |
+-------------+--------------------+-------------+---------+-------+
| EVENT       | mysql              | %           | NO      | NO    |
| EVENT       | performance_schema | %           | NO      | NO    |
| EVENT       | information_schema | %           | NO      | NO    |
| EVENT       | %                  | %           | YES     | YES   |
| FUNCTION    | mysql              | %           | NO      | NO    |
| FUNCTION    | performance_schema | %           | NO      | NO    |
| FUNCTION    | information_schema | %           | NO      | NO    |
| FUNCTION    | %                  | %           | YES     | YES   |
| PROCEDURE   | mysql              | %           | NO      | NO    |
| PROCEDURE   | performance_schema | %           | NO      | NO    |
| PROCEDURE   | information_schema | %           | NO      | NO    |
| PROCEDURE   | %                  | %           | YES     | YES   |
| TABLE       | mysql              | %           | NO      | NO    |
| TABLE       | performance_schema | %           | NO      | NO    |
| TABLE       | information_schema | %           | NO      | NO    |
| TABLE       | %                  | %           | YES     | YES   |
| TRIGGER     | mysql              | %           | NO      | NO    |
| TRIGGER     | performance_schema | %           | NO      | NO    |
| TRIGGER     | information_schema | %           | NO      | NO    |
| TRIGGER     | %                  | %           | YES     | YES   |
+-------------+--------------------+-------------+---------+-------+
20 rows in set (0.01 sec)

デフォルトで入っているmysqlデータベース(権限などシステム管理用のデータベース)、information_schemaデータベース(MySQLの内部情報をSQLで参照するための疑似データベース)、performance_schemaデータベースは、他のテーブルの設定に関わらずENABLED = NOが設定されています。パフォーマンススキーマの統計情報は全ての条件をクリアした場合のみ(どれか1つの設定でもENABLED = NOになっている場合は取得されない)記録されるため、特定のテーブルのみ参照し、その他にもオーバーヘッドを抑えたい場合などにはこのテーブルが有効かも知れません。

パフォーマンススキーマの参照

パフォーマンススキーマから統計情報を引き出すには、performance_schemaデータベースのsetup_*以外のテーブルにアクセスします。テーブルの名前と、そのテーブルにアクセスして確認できる統計情報は概ね一致しているので、まずはテーブルの名前で興味をそそられるものを探して開いてみるのが良いでしょう。

mysql> SELECT * FROM file_instances;
+----------------------------------------------------------------------------------------------------+---------------------------------------------+------------+
| FILE_NAME                                                                                          | EVENT_NAME                                  | OPEN_COUNT |
+----------------------------------------------------------------------------------------------------+---------------------------------------------+------------+
| /usr/mysql/5.7.13/share/english/errmsg.sys                                                         | wait/io/file/sql/ERRMSG                     |          0 |
| /usr/mysql/5.7.13/share/charsets/Index.xml                                                         | wait/io/file/mysys/charset                  |          0 |
| /usr/mysql/5.7.13/keyring/keyring                                                                  | wait/io/file/keyring_file/keyring_file_data |          0 |
| /usr/mysql/5.7.13/data/ibdata1                                                                     | wait/io/file/innodb/innodb_data_file        |          3 |
..
| /usr/mysql/5.7.13/data/p_s/file_instances.frm                                                      | wait/io/file/sql/FRM                        |          0 |
+----------------------------------------------------------------------------------------------------+---------------------------------------------+------------+
188 rows in set (0.00 sec)

これらのテーブルは概して横に長い(カラム数が多く、格納されている文字列も長い)ことが多いため、MySQL WorkbenchなどのGUIツールを使うか、mysqlコマンドラインクライアントのpager less -Sサブコマンドなどで見ることをお勧めします。

setup_*テーブルと違い、これらのテーブルはTRUNCATEすることで「今まで蓄積した統計情報をリセット」できます。パフォーマンススキーマの統計は累積値なので、何らかのチューニングを実施してその効果を測りたい場合は一度統計をリセットすると良いでしょう(リセット前の情報も保管しておきたい場合はSQLでアクセスして任意のスキーマにINSERT .. SELECTステートメントでテーブル情報をコピーすれば良い)。なお、PERFORMANCE_SCHEMAストレージエンジンはメモリー上にデータを蓄積するため、MySQLを再起動した場合はそれまでの統計情報はリセットされます。

パフォーマンススキーマが集めた統計情報の他に、ストレージエンジンとしてのPERFORMANCE_SCHEMAも自身の情報を多少収集しています。この情報にはSHOW ENGINE performance_schema STATUSでアクセスできます(SHOW ENGINE INNODB STATUSPERFORMANCE_SCHEMAストレージエンジン版)。

mysql57> SHOW ENGINE PERFORMANCE_SCHEMA STATUS;
+--------------------+-------------------------------------------------------------+----------+
| Type               | Name                                                        | Status   |
+--------------------+-------------------------------------------------------------+----------+
| performance_schema | events_waits_current.size                                   | 176      |
| performance_schema | events_waits_current.count                                  | 1536     |
| performance_schema | events_waits_history.size                                   | 176      |
| performance_schema | events_waits_history.count                                  | 2560     |
| performance_schema | events_waits_history.memory                                 | 450560   |
..
| performance_schema | performance_schema.memory                                   | 94739320 |
+--------------------+-------------------------------------------------------------+----------+
229 rows in set (0.00 sec)

各テーブルに記録されている統計の個数、記録された回数、記録に利用しているメモリー量などを確認できます。特に最後の1行「パフォーマンススキーマ全体でどれくらいのメモリーを利用しているか」は注意して見るようにしましょう。

sysとは

sysは、パフォーマンススキーマの情報を見やすくするためのビューやストアドファンクション、ストアドプロシージャの集まりです。名前空間としてsysデータベースを利用するため、もっぱら sysスキーマ(MySQLではスキーマとデータベースは同じものを指す)と呼ばれることが多いです。パフォーマンススキーマを前提としたビューが主な機能なので、performance_schema = OFFの状態ではほとんどのビューは結果を返しません。

MySQL 5.7ではデータベースを初期化(mysqld --initialize)した時点でsysデータベースが作成されますが、MySQL 5.6ではGitHubのmysql-sysリポジトリーからスクリプトをダウンロードして実行する必要があります(ビュー、関数、ストアドプロシージャなのでインストールというよりはCREATE VIEWなどが並んだsqlスクリプトを実行するだけ)。また、MySQL 5.5以前(そもそもパフォーマンススキーマが実装されていなかった)には対応していません。

sysのセットアップ(MySQL 5.6向け)

MySQL 5.6向けのセットアップ手順は以下の通りです。URLやファイル名などは2016/07/12現在のもので、将来変更になる可能性があります。

$ git clone https://github.com/mysql/mysql-sys.git
Initialized empty Git repository in /root/mysql-sys/.git/
remote: Counting objects: 3009, done.
remote: Total 3009 (delta 0), reused 0 (delta 0), pack-reused 3008
Receiving objects: 100% (3009/3009), 1.17 MiB | 466 KiB/s, done.
Resolving deltas: 100% (1768/1768), done.

$ cd mysql-sys
$ mysql -uroot -p < sys_56.sql

$ mysql -uroot -p
mysql> SHOW DATABASES;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.01 sec)

sys_56.sqlを実行する際、mysqlコマンドラインクライアントに-vオプションを与えて実行すると、画面にステートメントを出力できます(-vオプションなしでそのまま実行すると、何も表示されずにプロンプトが返ってくる)。 sys_56.sqlはセッションのバイナリーログをオフにするため、マスターで実行してもスレーブにsysデータベースは作成されません。

sysの便利機能

sysには多くのビュー、ストアドファンクション、ストアドプロシージャが存在します。完全なリストはドキュメントで確認できますが、ここでは筆者が実運用上で役立てているいくつかの機能を紹介します。

sys.statement_analysis

statement_analysisは、performance_schema.events_statements_summary_by_digestの内容を人間が見やすい形に整形したビューです。

mysql> SELECT * FROM statement_analysis\G
..
*************************** 2. row ***************************
            query: SELECT `c` FROM `sbtest1` WHERE `id` = ?
               db: sbtest
        full_scan:
       exec_count: 23890
        err_count: 0
       warn_count: 0
    total_latency: 2.36 s
      max_latency: 521.15 us
      avg_latency: 98.74 us
     lock_latency: 778.65 ms
        rows_sent: 23890
    rows_sent_avg: 1
    rows_examined: 23890
rows_examined_avg: 1
    rows_affected: 0
rows_affected_avg: 0
       tmp_tables: 0
  tmp_disk_tables: 0
      rows_sorted: 0
sort_merge_passes: 0
           digest: 80295d1d2720d4515b05d648e8caa82f
       first_seen: 2016-07-12 17:04:40
        last_seen: 2016-07-12 17:04:53
..

queryカラムは文字数によってsys.format_statement関数で切り詰めて表示されます(切り詰められたくない場合はx$statement_analysisテーブルを参照。statement_analysisに限らず、sysデータベースのビューにはx$接頭辞を持つものが対として存在しており、それらは切り詰めの関数を通さなくなっている)。表示される単位は「ダイジェスト」であり、例えばSELECT c FROM sbtest1 WHERE id = 1SELECT c FROM sbtest1 WHERE id = 2は定数部分がノーマライズされて同じダイジェストを持ちます。

記録されている値は累積の統計値のためスローログのように時系列変化を追うことはできませんが、スローログに記録されないような「1回ずつの実行時間は閾値未満だが、多くの回数実行されて累計の処理時間が長いもの」や「テンポラリーテーブルをDisk上に出力する必要があったもの」、「rows_examinedに対してrows_sentが圧倒的に少なく(x$statement_analysisを利用する場合、 ORDER BY rows_examined / rows_sent DESCでソートできる)インデックス効率が悪そうなもの」などを抽出できます。

sys.innodb_lock_waits

innodb_lock_waitsは、information_schemainnodb_trxinnodb_locksinnodb_lock_waitsを結合したビューです(information_schemaを利用しているため、パフォーマンススキーマの有効/無効に関わらず利用できる)。

mysql57> SELECT * FROM innodb_lock_waits\G
*************************** 1. row ***************************
                wait_started: 2016-07-12 17:49:06
                    wait_age: 00:00:13
               wait_age_secs: 13
                locked_table: `d1`.`user`
                locked_index: PRIMARY
                 locked_type: RECORD
              waiting_trx_id: 8063
         waiting_trx_started: 2016-07-12 17:49:06
             waiting_trx_age: 00:00:13
     waiting_trx_rows_locked: 1
   waiting_trx_rows_modified: 0
                 waiting_pid: 320
               waiting_query: SELECT * FROM user LIMIT 3 FOR UPDATE
             waiting_lock_id: 8063:146:3:2
           waiting_lock_mode: X
             blocking_trx_id: 8062
                blocking_pid: 321
              blocking_query: NULL
            blocking_lock_id: 8062:146:3:2
          blocking_lock_mode: X
        blocking_trx_started: 2016-07-12 17:49:06
            blocking_trx_age: 00:00:13
    blocking_trx_rows_locked: 3
  blocking_trx_rows_modified: 0
     sql_kill_blocking_query: KILL QUERY 321
sql_kill_blocking_connection: KILL 321
1 row in set (0.01 sec)

上記のように、待っているクエリー、待たせているクエリーを一覧できます。InnoDBのロックを確認するといえばMySQL InnoDBにおけるロック競合の解析手順 - SH2の日記が有名ですが、同等以上の情報を確認できるビューを利用できるのは嬉しいところです(筆者は必要になるたび、このブログのステートメントからビューを作っていた)。

sys.ps_truncate_all_tables

ps_truncate_all_tablesは、パフォーマンススキーマに蓄積された統計情報をリセットするためのストアドプロシージャです。パフォーマンススキーマに蓄積された情報はテーブルをTRUNCATEすることでリセットができることは先に触れましたが、 performance_schemaデータベース(記録系のテーブルのみ。setup_*は対象外)の全てのテーブルにTRUNCATEを実行することで統計情報をクリアします(関数の名前通りの動き)。

mysql> CALL sys.ps_truncate_all_tables(0);
+---------------------+
| summary             |
+---------------------+
| Truncated 44 tables |
+---------------------+
1 row in set (0.01 sec)

Query OK, 0 rows affected (0.01 sec)

引数には"0"または"1"を指定します。"1"を指定した場合、全てのTRUNCATEステートメントが実行と同時に表示されます。やっていることがシンプルなだけに胸を張って「これがsysの機能の1つ」というのは若干憚られますが、 筆者は"a set of objects that helps DBAs and developers interpret data collected by the Performance Schema"(https://dev.mysql.com/doc/refman/5.7/en/sys-schema.html)というsysの目標に非常によく沿った関数だと考えています。

その他のsysのオブジェクト

sysデータベースにはいくつものビューが格納されていますが、ほとんどのビューは名前からその用途が想像できます。statement_analysisを参照してWHEREでフィルターをかけたり、ORDER BYでソートし直しても特に不便はないため、筆者はあまり別のビューは利用していません。

sysデータベースにはいくつものビューが格納されていますが、ほとんどのビューは名前からその用途が想像できます。statement_analysisを参照してWHEREでフィルターをかけたり、ORDER BYでソートし直したりしても特に不便はないため、筆者はあまり別のビューは利用していません。

sysのビューの多くはx$接頭辞がついた同じ名前のビューを持っています。パフォーマンススキーマはもともとナノ秒(ns)単位でレイテンシーを記録しますが、ナノ秒は人間がパッと見るには不向きな単位です。そこでsysのビューでは原則sys.format_timeストアドファンクションを利用して、1000ナノ秒を1マイクロ秒(1000ns= 1us)に、1000マイクロ秒を1ミリ秒(1000us = 1ms)に、1000ミリ秒を1秒(1000ms = 1s)に、60秒を1分(60s = 1m)に、60分を1時間(60m = 1h)に、24時間を1日(24h = 1d)に、7日を1週(7d = 1w)に変換して表示します(筆者としては"分"以降の単位は余計なお世話だと考えるが)。

この変換は見る分には便利ですが、変換後の値は「単位まで含めた文字列」として扱われてしまうため、ソートしようとした場合に問題になります(例えば"1ms"と"1us"をORDER BY DESC比較すると、"u"の方が"m"よりも後に来るため、"1us", "1ms"の順にソートされてしまう)。このような場合はx$接頭辞のビューを利用するとナノ秒のまま整数値として扱えるので、WHERE句、ORDERBY句のみをx$ビューで処理してdigestカラムなどでJOINし、表示はx$でない方を利用すると見やすくなります。

mysql> SELECT statement_analysis.* FROM x$statement_analysis JOIN statement_analysis USING(digest) ORDER BY x$statement_analysis.avg_latency DESC LIMIT 3;
+-------------------------------------------------------------------+------+-----------+------------+-----------+------------+---------------+-------------+-------------+--------------+-----------+---------------+---------------+-------------------+---------------+-------------------+------------+-----------------+-------------+-------------------+----------------------------------+---------------------+---------------------+
| query                                                             | db   | full_scan | exec_count | err_count | warn_count | total_latency | max_latency | avg_latency | lock_latency | rows_sent | rows_sent_avg | rows_examined | rows_examined_avg | rows_affected | rows_affected_avg | tmp_tables | tmp_disk_tables | rows_sorted | sort_merge_passes | digest                           | first_seen          | last_seen           |
+-------------------------------------------------------------------+------+-----------+------------+-----------+------------+---------------+-------------+-------------+--------------+-----------+---------------+---------------+-------------------+---------------+-------------------+------------+-----------------+-------------+-------------------+----------------------------------+---------------------+---------------------+
| SELECT * FROM SYSTEM_USER LIMIT ? FOR UPDATE                      | d1   |           |          4 |         1 |          0 | 1.00 h        | 1.00 h      | 15.00 m     | 2.02 ms      |         9 |             2 |             9 |                 2 |             0 | 0                 |          0 |               0 |           0 |                 0 | d5474c388bde037685b236bfd3b09573 | 2016-07-12 17:48:54 | 2016-07-12 18:49:07 |
| DROP SCHEMA `d1`                                                  | NULL |           |          1 |         0 |          0 | 46.29 ms      | 46.29 ms    | 46.29 ms    | 41.94 ms     |         0 |             0 |             0 |                 0 |             6 | 6                 |          0 |               0 |           0 |                 0 | aa246c9d2acb3f947ac3baf335bae205 | 2016-07-15 19:46:08 | 2016-07-15 19:46:08 |
| SELECT `sys` . `format_stateme ... cy` , `sys` . `format_time` (  | sys  | *         |          3 |         0 |          0 | 66.79 ms      | 36.17 ms    | 22.26 ms    | 28.07 ms     |        93 |            31 |           187 |                62 |             0 | 0                 |          0 |               0 |          93 |                 0 | 537d3840a8bc9fee4fd63febaab85365 | 2016-07-19 09:01:28 | 2016-07-19 09:08:24 |
+-------------------------------------------------------------------+------+-----------+------------+-----------+------------+---------------+-------------+-------------+--------------+-----------+---------------+---------------+-------------------+---------------+-------------------+------------+-----------------+-------------+-------------------+----------------------------------+---------------------+---------------------+
3 rows in set (0.03 sec)

まとめ

パフォーマンススキーマはMySQL 5.6で大きく機能、性能が改善されました。MySQL 5.6以降ではデフォルトでONになっています。パフォーマンススキーマの設定はperformance_schemaデータベースのsetup_*テーブルにUPDATEすることで変更できます。パフォーマンススキーマのデフォルト設定(performance_schema.setup_*テーブルの初期値)のままでも改善に役立つ情報が蓄積されるため、特に理由がなければ有効にしておくことをお勧めします。

sysはパフォーマンススキーマの情報を見やすくするためのビューやストアドプロシージャの集合です。パフォーマンススキーマ、sysともSQLでアクセスできるため、SELECTを工夫することで様々な情報にアクセスしたりデータを保管したりできます。

GMOメディア株式会社

GMOメディア株式会社のDBAで日本MySQLユーザ会員。Oracle ACE(MySQL)、MySQL 5.7 Community Contributor Award 2015受賞。ぬいぐるみとイルカが好きなおじさん。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています