MySQLのチューニング調査依頼で時短で終わるように
バージョン
- CentOS7
- MySQL5.6
もくじ
DB, テーブルのDBエンジンの確認
データベースの確認
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | exampledb | +--------------------+ 4 rows in set (0.00 sec)
デフォルトのエンジンの確認
mysql> show engines; +--------------------+---------+----------------------------------------------------------------+--------------+------+------------+ | Engine | Support | Comment | Transactions | XA | Savepoints | +--------------------+---------+----------------------------------------------------------------+--------------+------+------------+ | FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL | | MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO | | MyISAM | YES | MyISAM storage engine | NO | NO | NO | | BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO | | CSV | YES | CSV storage engine | NO | NO | NO | | MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO | | ARCHIVE | YES | Archive storage engine | NO | NO | NO | | InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES | | PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO | +--------------------+---------+----------------------------------------------------------------+--------------+------+------------+ 9 rows in set (0.00 sec)
DBエンジンの確認 例) exampledbの各テーブルのエンジンの確認
mysql> use information_schema; mysql> select table_name, engine from tables where table_schema = "exampledb"; +------------------------+--------+ | table_name | engine | +------------------------+--------+ | wp_commentmeta | InnoDB | | wp_comments | InnoDB | | wp_cptch_images | InnoDB | | wp_cptch_packages | InnoDB | | wp_cptch_whitelist | InnoDB | | wp_links | InnoDB | | wp_options | InnoDB | | wp_popularpostsdata | InnoDB | | wp_popularpostssummary | InnoDB | | wp_postmeta | InnoDB | | wp_posts | InnoDB | | wp_term_relationships | InnoDB | | wp_term_taxonomy | InnoDB | | wp_termmeta | InnoDB | | wp_terms | InnoDB | | wp_user_login_log | InnoDB | | wp_usermeta | InnoDB | | wp_users | InnoDB | | wp_wp_rp_tags | InnoDB | +------------------------+--------+ 19 rows in set (0.00 sec)
InnoDBなのか、MyISAMなのか・・・それ以外なのかによってチューニングパラメータは異なる。1つのサーバに異なるエンジンが混在していないのが望ましい。
グローバルパラメータの確認
実際に有効になっているパラメータを確認する
グローバルパラメータの確認
mysql> SHOW GLOBAL VARIABLES; +--------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Variable_name | Value | +--------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | auto_increment_increment | 1 | | auto_increment_offset | 1 | | autocommit | ON | | automatic_sp_privileges | ON | | avoid_temporal_upgrade | OFF | | back_log | 92 | (略) | | updatable_views_with_limit | YES | | version | 5.6.37-log | | version_comment | MySQL Community Server (GPL) | | version_compile_machine | x86_64 | | version_compile_os | Linux | | wait_timeout | 60 | +--------------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 440 rows in set (0.00 sec)
ステータスの確認
mysql> SHOW GLOBAL STATUS; +-----------------------------------------------+-------------+ | Variable_name | Value | +-----------------------------------------------+-------------+ | Aborted_clients | 0 | | Aborted_connects | 1 | | Binlog_cache_disk_use | 1461 | | Binlog_cache_use | 453258 | (略) | Tc_log_page_size | 0 | | Tc_log_page_waits | 0 | | Threads_cached | 22 | | Threads_connected | 1 | | Threads_created | 23 | | Threads_running | 1 | | Uptime | 4309136 | | Uptime_since_flush_status | 4309136 | +-----------------------------------------------+-------------+ 341 rows in set (0.00 sec)
パフォーマンススキーマ
mysql> SHOW GLOBAL VARIABLES LIKE 'performance_schema%'; +--------------------------------------------------------+-------+ | Variable_name | Value | +--------------------------------------------------------+-------+ | performance_schema | ON | | performance_schema_accounts_size | 100 | | performance_schema_digests_size | 5000 | | performance_schema_events_stages_history_long_size | 1000 | | performance_schema_events_stages_history_size | 10 | | performance_schema_events_statements_history_long_size | 1000 | | performance_schema_events_statements_history_size | 10 | | performance_schema_events_waits_history_long_size | 1000 | | performance_schema_events_waits_history_size | 10 | | performance_schema_hosts_size | 100 | | performance_schema_max_cond_classes | 80 | | performance_schema_max_cond_instances | 1255 | | performance_schema_max_digest_length | 1024 | | performance_schema_max_file_classes | 50 | | performance_schema_max_file_handles | 32768 | | performance_schema_max_file_instances | 1750 | | performance_schema_max_mutex_classes | 200 | | performance_schema_max_mutex_instances | 4489 | | performance_schema_max_rwlock_classes | 40 | | performance_schema_max_rwlock_instances | 2306 | | performance_schema_max_socket_classes | 10 | | performance_schema_max_socket_instances | 320 | | performance_schema_max_stage_classes | 150 | | performance_schema_max_statement_classes | 168 | | performance_schema_max_table_handles | 572 | | performance_schema_max_table_instances | 556 | | performance_schema_max_thread_classes | 50 | | performance_schema_max_thread_instances | 378 | | performance_schema_session_connect_attrs_size | 512 | | performance_schema_setup_actors_size | 100 | | performance_schema_setup_objects_size | 100 | | performance_schema_users_size | 100 | +--------------------------------------------------------+-------+ 32 rows in set (0.00 sec)
オープンになっているテーブルの状況が見れる
mysql> SHOW OPEN TABLES;
プロシージャの確認
mysql> SHOW PROCEDURE STATUS;
権限の確認
mysql> SHOW GRANTS;
エラー状況を確認
WARNINGクエリ確認
mysql> SHOW WARNINGS;
ERRORクエリの確認
mysql> SHOW ERRORS;
障害発生時にログインして、MySQLサービスが再起動したかを確認する
mysql> SHOW GLOBAL STATUS LIKE 'uptime';
クエリの実行状況が見れる
mysql> SHOW PROCESSLIST; +--------+------+-----------+------+---------+------+-------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +--------+------+-----------+------+---------+------+-------+------------------+ | 303072 | root | localhost | NULL | Query | 0 | init | SHOW PROCESSLIST | +--------+------+-----------+------+---------+------+-------+------------------+ 1 row in set (0.00 sec)
デッドロック ロック待ちの確認
mysql> SHOW PROCESSLIST\G *************************** 1. row *************************** Id: 303072 User: root Host: localhost db: NULL Command: Query Time: 0 State: init Info: SHOW PROCESSLIST 1 row in set (0.00 sec)
これはOK
mysql> SHOW PROCESSLIST\G *************************** 1. row *************************** ・・・・・・・・ Time: 55 State: Locked ←!!!! ・・・・・・・・
こうなっていたらまずい
ロック時にSHOW ENGINE INNODB STATUSコマンドでロック原因を特定できるようにする
# vi /etc/my.cnf # デッドロック関連のログをエラーログに出力させる innodb_print_all_deadlocks=ON # ロックモニターの有効化:SHOW ENGINE INNODB STATUSでロック原因を特定できるようにする innodb_status_output=ON innodb_status_output_locks=ON
デッドロック発生時にタイムアウトを設定する
# vi /etc/my.cnf ## デッドロック ==================================== #テーブルロックタイムアウト時間 必須 初期値50秒 innodb_lock_wait_timeout = 5
クエリキャッシュ
注意
- INSERTが多いシステムでは逆にパフォーマンスが悪くなり向かない
クエリキャッシュを利用する為に広範囲でロックを取るのでロック競合する - SELECT主体の参照が多いサイトでは向いている
- MySQL8.0では廃止された
設定にクエリキャッシュ関連のディレクティブがあると起動しない
クエリキャッシュを削除する場合
mysql> RESET QUERY CACHE;
クエリキャッシュヒット状況の確認
mysql> SHOW STATUS LIKE 'Qcache%'; +-------------------------+-----------+ | Variable_name | Value | +-------------------------+-----------+ | Qcache_free_blocks | 3 | | Qcache_free_memory | 132631016 | | Qcache_hits | 110 | | Qcache_inserts | 179 | | Qcache_lowmem_prunes | 0 | | Qcache_not_cached | 31 | | Qcache_queries_in_cache | 97 | | Qcache_total_blocks | 211 | +-------------------------+-----------+ 8 rows in set (0.00 sec)
- Qcache_free_blocks
キャッシュに割り当てが出来るフリーのブロック数
1SQLキャッシュするのに1ブロック最低消費される - Qcache_free_memory
クエリキャッシュに割り当てができるフリーのメモリ - Qcache_hits
クエリのヒット数 - Qcache_lowmem_prunes
メモリがないので削除されたクエリキャッシュ
すべてのキャッシュがメモリに載っていればここは0になる - Qcache_not_cached
キャッシュに入れられなかったクエリの数 - Qcache_queries_in_cache
キャッシュ内のクエリの数 - Qcache_total_blocks
ブロック領域の合計
クエリキャッシュ?
- クエリキャッシュはSELECTクエリの結果をキャッシュしたものです。
- まったく同じSELECTクエリが来た場合にキャッシュを返します。
クエリキャッシュヒット率の確認
mysql> SELECT (SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'QCACHE_HITS')/(SELECT SUM(VARIABLE_VALUE) FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME IN ('QCACHE_HITS','QCACHE_INSERTS','QCACHE_NOT_CACHED'))*100 AS CACHE_HIT_RATE; +--------------------+ | CACHE_HIT_RATE | +--------------------+ | 49.033816425120776 | +--------------------+ 1 row in set (0.00 sec)
キャッシュがどれだけヒットしているか
query_cache_limitの確認
mysql> SHOW GLOBAL VARIABLES LIKE 'query_cache_limit'; +-------------------+---------+ | Variable_name | Value | +-------------------+---------+ | query_cache_limit | 2097152 | +-------------------+---------+ 1 row in set (0.00 sec)
2MBに設定済。
2MB~4MBにする
query_cache_sizeの確認
mysql> SHOW GLOBAL VARIABLES LIKE 'query_cache_size'; +------------------+-----------+ | Variable_name | Value | +------------------+-----------+ | query_cache_size | 134217728 | +------------------+-----------+ 1 row in set (0.00 sec)
128MBに設定済。1年後のDBサイズの20%程度が目安とされる。
128MB~256MB程度まで。クエリキャッシュが多すぎてもキャッシュ保守にリソースが回されて逆に遅くなる。大きくし過ぎてもいけない。
スロークエリ対応
スロークエリ有効化 1秒以上かかるクエリを出力する
mysql> SET GLOBAL slow_query_log=ON mysql> SET GLOBAL slow_query_log_file=/var/lib/mysql/mysql-slow.log mysql> SET GLOBAL long_query_time=1
遅い順にソートする
$ mysqldumpslow -s t /var/lib/mysql/mysql-slow.log
EXPLAIN EXTENDEDによるクエリの解析
mysql> EXPLAIN EXTENDED <SQLクエリ>\G
typeに注目する
良いtype
- const
PRIMARY KEYまたはUNIQUEインデックスによる検索で最速 - eq_ref
JOINにてPRIARY KEYまたはUNIQUE KEYが利用される時 - ref
ユニークでないインデックスによる検索。WHERE name = valueのような時 - range
ユニークを用いた範囲検索
あまり良くないtype
- index
フルインデックススキャン。インデックス全体を見るので遅い - ALL
フルテーブルスキャン。インデックスが利用されていない!
スロークエリでなければ問題ない。
mysql> EXPLAIN EXTENDED <SQL文>\G *********************** 1. row *********************** ・・・ type: index ・・・ rows: 1000 ・・・ *********************** 2. row *********************** ・・・ type: index_subquery ・・・ rows: 200 ・・・
1000 × 200行が対象になっている。減らせないか?
mysql> EXPLAIN EXTENDED SELECT post_title, post_date, post_status FROM wp_posts \G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: wp_posts type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 7799 filtered: 100.00 Extra: NULL 1 row in set, 1 warning (0.00 sec) ERROR: No query specified
ALLはフルテーブルスキャン。インデックスが利用されていないことを示す
mysql> EXPLAIN EXTENDED SELECT * FROM wp_posts WHERE post_status = "publish" AND post_type = "post" \G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: wp_posts type: ref possible_keys: type_status_date key: type_status_date key_len: 164 ref: const,const rows: 634 filtered: 100.00 Extra: Using index condition 1 row in set, 1 warning (0.00 sec) ERROR: No query specified
ref。ユニーク(PRIMARY or UNIQUE)でないインデックスを使って等価検索を行った時に利用されるアクセスタイプ。
WHEREで検索されるキーとなるカラムがインデックスされていなければインデックスを張る
mysql> ALTER TABLE <テーブル名> ADD INDEX(<カラム名>)
対象カラムがユニークになっているようにする
mysql> ALTER TABLE <テーブル名> ADD UNIQUE(<カラム名>)
インデックス関連
チューニングツールの利用
ファイルディスクリプタ
ジェネラルログを出力する
フレームワークでORMのクエリを出力する時など、すべてのクエリを見たい時に
mysql> SET GLOBAL general_log='on' mysql> SET GLOBAL general_log_file=/var/lib/mysql/general.log
優技録のコンフィグ 4CPU 4GB
※2019年01月25日 2CPU 2GBにスケールダウン ボトルネックの改善による省リソースハック成功
# cat /etc/my.cnf [mysqld] ##レプリケーション Master ================================== binlog-do-db = exampledb # レプリケーション対象DB binlog-ignore-db = mysql # レプリケーションしないDB server-id = 1 log-bin = mysql-bin relay-log = relay-log #bind-address = 0.0.0.0 expire_logs_days = 10 max_binlog_size = 128M binlog_format = mixed #マスタートランザクション sync_binlog = 1 innodb_support_xa = 1 innodb_flush_log_at_trx_commit = 1 ## 準同期マスター側設定 #plugin-load=rpl_semi_sync_master=semisync_master.so #rpl_semi_sync_master_enabled=1 #rpl_semi_sync_master_timeout=5000 ####################### ================================== ## MySQLデータディレクトリの指定場所 datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock user=mysql pid-file=/var/run/mysqld/mysqld.pid # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 character-set-server = utf8 skip-character-set-client-handshake lower_case_table_names skip-name-resolve default-storage-engine=InnoDB sql_mode='' ##タイムスタンプ 5.6~ explicit_defaults_for_timestamp = true #リカバリ どうしても起動しない時に1ずつ数値をあげて再起動させる。 #innodb_force_recovery = 1 #####================================================================================= #グローバルバッファ mysqlデーモン全体で一つだけ確保されるバッファ #スレッドバッファ mysqlのスレッド(コネクション)単位で確保されるバッファ #公式 グローバルバッファ + (スレッドバッファ × コネクション数) = メモリ使用量 #####================================================================================= ## 最大接続数 max_connections = 1024 ### グローバルバッファ ##################============================================= innodb_buffer_pool_size = 2G ##重要 全物理メモリの70~80%が目安 or 2年後のDB最大容量Xの120%以上 設定容量分だけディスクに書き込まれている分メモリに ##5.6から廃止 innodb_additional_mem_pool_size = 16M innodb_use_sys_malloc = 1 ##InnoDBの内部データなどを保持するための領域 innodb_file_per_table ##テーブル毎にテーブルスペースが作成される innodb_autoextend_increment = 64M ##InnoDB自動拡張サイズ #無効化#innodb_data_file_path=ibdata1:10G:autoextend:max:100G ## 安全弁 innodb_log_files_in_group = 4 ##ロググループのログファイル数 innodb_log_file_size = 128M ##Innodbロググループの各ログファイルのサイズ 初期値:48M #無効化#innodb_flush_log_at_trx_commit = 1 ##1:トランザクション単位でログ出力し安全 ##2:1秒間に1回ログファイルに出力。冗長構成時は危険 innodb_thread_concurrency = 16 ##InnoDBが同時に処理することのできるスレッド数の上限 innodb_commit_concurrency = 10 ##InnoDBが同時にコミットする事ができるスレッドの数 #無効化#innodb_flush_method = O_DIRECT ##ハードウェアRAIDを使用している場合のみ可 初期値:fdatasync innodb_strict_mode ##エラーが発生時に警告のみでパフォーマンスには影響しない innodb_write_io_threads = 8 ##デフォルト値4 非同期IOの書き込みバックグラウンドスレッド数 innodb_read_io_threads = 8 ##デフォルト値4 非同期IOの読み込みバックグラウンドスレッド数 #無効化#innodb_fast_shutdown = 0 ##デフォルト値1 シャットダウン時にWALに残っていたデータを書き込み ### グローバルバッファ ここまで ##########============================================= ### スレッドバッファ ###################### key_buffer_size = 16M read_buffer_size = 256k read_rnd_buffer_size = 512k join_buffer_size = 256k sort_buffer_size = 512K ########################################### ## キャッシュ ########################## thread_cache_size = 128 table_open_cache = 4000 table_definition_cache = 400 ##クエリキャッシュ query_cache_size = 128M ## 重要 2年後のDB最大容量Xの10%以上が目安 query_cache_limit = 2M query_cache_min_res_unit = 4k query_cache_type = 1 ####################################### ## 接続最大時間 wait_timeout = 60 ##最大取扱いファイル数 open_files_limit = 5500 ## デッドロック ==================================== #テーブルロックタイムアウト時間 必須 初期値50秒 innodb_lock_wait_timeout = 5 #デッドロック関連のログをエラーログに出力させる innodb_print_all_deadlocks=ON # ロックモニターの有効化:ロック時にSHOW ENGINE INNODB STATUSでロック原因を特定できるようにする innodb_status_output=ON innodb_status_output_locks=ON ##================================================== ##この2つは同じ値にする事 tmp_table_size = 64M max_heap_table_size = 64M ## クライアントからサーバーに送信できるパケットの最大長 リストア出来るDB最大サイズ #無効化#max_allowed_packet = 8M max_allowed_packet = 4000M ## 重要 クエリキャッシュ 1年後のデータ総量Xの20% query_cache_size = 64M query_cache_limit = 2M query_cache_min_res_unit = 4k query_cache_type = 1 ## デバッグ ================================= ## スロークエリ slow_query_log = 1 long_query_time = 3 slow_query_log_file = /var/log/mysqld-slow.log ##無効化#log_queries_not_using_indexes ##無効化#log-slow-admin-statements ## 全てのクエリを記録 #general_log=1 #general_log_file=/var/log/general-query.log ##エラーログの確認 log-error=/var/log/mysqld-error.log #Aborted connection..のような警告をerror Logに書く log_warnings = 1 ##============================================ [mysqld_safe] log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid
Windows7, 2008以上のMySQLの場合
デフォルトでIPv6優先になっているので、IPv6優先かつlocalhostで接続になっている場合は遅くなる。
- IPv4優先
- 127.0.0.1で接続
// アプリサーバとDBサーバが別でIPによる接続しているなら問題ない - 特に強い理由がなければミニマルなLinux版MySQLにした方が速い