-- 找出执行次数最多的 SQL SELECT schema_name, DIGEST_TEXT, COUNT_STAR AS exec_count, TRUNCATE(AVG_TIMER_WAIT/1000000000000, 6) AS avg_time_s, TRUNCATE(MAX_TIMER_WAIT/1000000000000, 6) AS max_time_s, SUM_ROWS_EXAMINED AS total_rows_examined, SUM_ROWS_SENT AS total_rows_sent, SUM_CREATED_TMP_TABLES AS tmp_tables, SUM_CREATED_TMP_DISK_TABLES AS tmp_disk_tables FROM performance_schema.events_statements_summary_by_digest WHERE schema_name ISNOTNULL ORDERBY COUNT_STAR DESC LIMIT 10;
-- 找出平均执行时间最长的 SQL SELECT schema_name, DIGEST_TEXT, COUNT_STAR AS exec_count, TRUNCATE(AVG_TIMER_WAIT/1000000000000, 6) AS avg_time_s, TRUNCATE(SUM_TIMER_WAIT/1000000000000, 6) AS total_time_s FROM performance_schema.events_statements_summary_by_digest WHERE schema_name ISNOTNULL ORDERBY AVG_TIMER_WAIT DESC LIMIT 10;
-- 找出全表扫描最多的 SQL SELECT schema_name, DIGEST_TEXT, COUNT_STAR AS exec_count, SUM_NO_INDEX_USED AS full_scan_count, TRUNCATE(AVG_TIMER_WAIT/1000000000000, 6) AS avg_time_s FROM performance_schema.events_statements_summary_by_digest WHERE SUM_NO_INDEX_USED >0 ORDERBY SUM_NO_INDEX_USED DESC LIMIT 10;
-- 查看 I/O 最繁忙的表 SELECT object_schema, object_name, COUNT_STAR AS total_io, COUNT_READ AS read_count, COUNT_WRITE AS write_count, COUNT_FETCH AS fetch_count, COUNT_INSERT AS insert_count, COUNT_UPDATE AS update_count, COUNT_DELETE AS delete_count, TRUNCATE(SUM_TIMER_WAIT/1000000000000, 6) AS total_wait_s FROM performance_schema.table_io_waits_summary_by_table WHERE object_schema NOTIN ('mysql', 'performance_schema', 'information_schema', 'sys') ORDERBY SUM_TIMER_WAIT DESC LIMIT 10;
-- 查看读写比例 SELECT object_schema, object_name, COUNT_READ AS read_count, COUNT_WRITE AS write_count, ROUND(COUNT_READ /NULLIF(COUNT_WRITE, 0), 2) AS read_write_ratio FROM performance_schema.table_io_waits_summary_by_table WHERE object_schema NOTIN ('mysql', 'performance_schema') AND COUNT_STAR >0 ORDERBY COUNT_STAR DESC LIMIT 10;
实战案例: 找出热点表并优化
1 2 3 4 5 6 7 8 9 10 11
-- 1. 找出访问最频繁的表 SELECT object_schema, object_name, COUNT_STAR FROM performance_schema.table_io_waits_summary_by_table WHERE object_schema ='mydb' ORDERBY COUNT_STAR DESC LIMIT 5;
-- 2. 查看该表的索引使用情况 SELECT*FROM performance_schema.table_io_waits_summary_by_index_usage WHERE object_schema ='mydb'AND object_name ='orders';
-- 查看索引使用统计 SELECT object_schema, object_name, index_name, COUNT_STAR AS access_count, COUNT_READ AS read_count, COUNT_WRITE AS write_count, COUNT_FETCH AS fetch_count FROM performance_schema.table_io_waits_summary_by_index_usage WHERE object_schema NOTIN ('mysql', 'performance_schema') AND index_name ISNOTNULL ORDERBY COUNT_STAR DESC LIMIT 20;
-- 找出从未使用过的索引 SELECT object_schema, object_name, index_name FROM performance_schema.table_io_waits_summary_by_index_usage WHERE object_schema NOTIN ('mysql', 'performance_schema', 'sys') AND index_name ISNOTNULL AND index_name !='PRIMARY' AND COUNT_STAR =0 ORDERBY object_schema, object_name;
实战案例: 删除无用索引
1 2 3 4 5 6 7 8 9 10 11 12
-- 1. 找出未使用的索引 SELECT CONCAT('ALTER TABLE ', object_schema, '.', object_name, ' DROP INDEX ', index_name, ';') AS drop_index_sql FROM performance_schema.table_io_waits_summary_by_index_usage WHERE object_schema ='mydb' AND index_name ISNOTNULL AND index_name !='PRIMARY' AND COUNT_STAR =0;
-- 2. 在测试环境验证后执行删除 -- ALTER TABLE mydb.orders DROP INDEX idx_unused;
五、锁分析表
1. data_locks (MySQL 8.0+)
作用: 显示当前持有的数据锁(行锁、表锁)。
使用场景: 诊断死锁、锁等待问题。
1 2 3 4 5 6 7 8 9 10 11
-- 查看当前的锁信息 SELECT thread_id, object_schema, object_name, lock_type, lock_mode, lock_status, lock_data FROM performance_schema.data_locks WHERE object_schema NOTIN ('mysql', 'performance_schema', 'sys');
-- 查看锁等待关系 SELECT waiting.thread_id AS waiting_thread, waiting.object_schema, waiting.object_name, waiting.lock_mode AS waiting_lock_mode, blocking.thread_id AS blocking_thread, blocking.lock_mode AS blocking_lock_mode, blocking.lock_data FROM performance_schema.data_lock_waits w JOIN performance_schema.data_locks waiting ON w.requesting_engine_lock_id = waiting.engine_lock_id JOIN performance_schema.data_locks blocking ON w.blocking_engine_lock_id = blocking.engine_lock_id;
-- 找出阻塞源头(最上游的事务) SELECT blocking_thread_id, COUNT(*) AS blocked_count FROM performance_schema.data_lock_waits w JOIN performance_schema.data_locks blocking ON w.blocking_engine_lock_id = blocking.engine_lock_id GROUPBY blocking_thread_id ORDERBY blocked_count DESC;
实战案例: 解决锁等待
1 2 3 4 5 6 7 8 9 10 11 12 13
-- 1. 找出阻塞的线程 SELECT blocking_thread_id FROM performance_schema.data_lock_waits LIMIT 1;
-- 2. 找到对应的进程 ID SELECT processlist_id FROM performance_schema.threads WHERE thread_id =<blocking_thread_id>;
-- 3. 查看该进程正在执行的 SQL SELECT*FROM performance_schema.events_statements_current WHERE thread_id =<blocking_thread_id>;
-- 查看元数据锁 SELECT object_type, object_schema, object_name, lock_type, lock_status, owner_thread_id FROM performance_schema.metadata_locks WHERE object_schema NOTIN ('performance_schema');
实战案例: DDL 被阻塞
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
-- 场景: ALTER TABLE 一直卡住不动
-- 1. 查看哪些会话持有该表的元数据锁 SELECT*FROM performance_schema.metadata_locks WHERE object_name ='orders';
-- 2. 找出对应的 SQL SELECT t.thread_id, t.processlist_id, s.sql_text FROM performance_schema.threads t JOIN performance_schema.events_statements_current s ON t.thread_id = s.thread_id WHERE t.thread_id IN ( SELECT owner_thread_id FROM performance_schema.metadata_locks WHERE object_name ='orders' );
-- 3. KILL 掉长时间持有锁的会话 KILL <processlist_id>;
六、文件 I/O 分析表
1. file_summary_by_instance
作用: 统计每个文件的 I/O 操作。
使用场景: 找出 I/O 瓶颈文件。
1 2 3 4 5 6 7 8 9 10 11 12
-- 查看 I/O 最频繁的文件 SELECT file_name, event_name, COUNT_READ AS read_count, COUNT_WRITE AS write_count, ROUND(SUM_NUMBER_OF_BYTES_READ/1024/1024, 2) AS read_mb, ROUND(SUM_NUMBER_OF_BYTES_WRITE/1024/1024, 2) AS write_mb, TRUNCATE(SUM_TIMER_WAIT/1000000000000, 6) AS total_wait_s FROM performance_schema.file_summary_by_instance ORDERBY SUM_TIMER_WAIT DESC LIMIT 10;
七、内存使用分析表
1. memory_summary_by_thread_by_event_name
作用: 统计每个线程的内存使用情况。
使用场景: 找出内存消耗最多的会话。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
-- 查看每个线程的内存使用 SELECT t.processlist_id, t.processlist_user, t.processlist_host, m.event_name, ROUND(m.current_allocated/1024/1024, 2) AS current_mb, ROUND(m.high_allocated/1024/1024, 2) AS high_mb FROM performance_schema.memory_summary_by_thread_by_event_name m JOIN performance_schema.threads t ON m.thread_id = t.thread_id WHERE m.current_allocated >0 AND t.processlist_id ISNOTNULL ORDERBY m.current_allocated DESC LIMIT 10;
2. memory_summary_global_by_event_name
作用: 全局内存使用统计。
使用场景: 查看哪些内存分配事件占用最多。
1 2 3 4 5 6 7 8 9
SELECT event_name, current_count, ROUND(current_allocated/1024/1024, 2) AS current_mb, ROUND(high_allocated/1024/1024, 2) AS high_mb FROM performance_schema.memory_summary_global_by_event_name WHERE current_allocated >0 ORDERBY current_allocated DESC LIMIT 10;
-- 开启语句级监控 UPDATE performance_schema.setup_instruments SET ENABLED ='YES', TIMED ='YES' WHERE NAME LIKE'statement/%';
-- 开启表 I/O 监控 UPDATE performance_schema.setup_instruments SET ENABLED ='YES', TIMED ='YES' WHERE NAME LIKE'wait/io/table/%';
-- 开启文件 I/O 监控 UPDATE performance_schema.setup_instruments SET ENABLED ='YES', TIMED ='YES' WHERE NAME LIKE'wait/io/file/%';
-- 开启锁监控 UPDATE performance_schema.setup_instruments SET ENABLED ='YES', TIMED ='YES' WHERE NAME LIKE'wait/lock/%';
-- 开启消费者 UPDATE performance_schema.setup_consumers SET ENABLED ='YES' WHERE NAME IN ( 'events_statements_current', 'events_statements_history', 'events_statements_history_long', 'statements_digest' );
实战场景: 性能诊断案例
场景 1: 找出系统中最慢的 SQL
1 2 3 4 5 6 7 8 9 10 11 12 13 14
-- 方法 1: 通过 events_statements_summary_by_digest SELECT schema_name, DIGEST_TEXT, COUNT_STAR AS exec_count, TRUNCATE(AVG_TIMER_WAIT/1000000000000, 6) AS avg_time_s, TRUNCATE(MAX_TIMER_WAIT/1000000000000, 6) AS max_time_s FROM performance_schema.events_statements_summary_by_digest WHERE schema_name ISNOTNULL ORDERBY AVG_TIMER_WAIT DESC LIMIT 10;
-- 查看当前的锁等待 SELECT w.requesting_thread_id AS waiting_thread, w.blocking_thread_id AS blocking_thread, waiting.sql_text AS waiting_sql, blocking.sql_text AS blocking_sql FROM performance_schema.data_lock_waits w JOIN performance_schema.threads t_waiting ON w.requesting_thread_id = t_waiting.thread_id JOIN performance_schema.threads t_blocking ON w.blocking_thread_id = t_blocking.thread_id LEFTJOIN performance_schema.events_statements_current waiting ON t_waiting.thread_id = waiting.thread_id LEFTJOIN performance_schema.events_statements_current blocking ON t_blocking.thread_id = blocking.thread_id;
场景 3: 分析表的访问模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
-- 查看表的读写比例 SELECT object_schema, object_name, COUNT_READ AS read_ops, COUNT_WRITE AS write_ops, CASE WHEN COUNT_WRITE >0THEN ROUND(COUNT_READ / COUNT_WRITE, 2) ELSE COUNT_READ ENDAS read_write_ratio, ROUND(SUM_TIMER_WAIT/1000000000000, 2) AS total_wait_s FROM performance_schema.table_io_waits_summary_by_table WHERE object_schema NOTIN ('mysql', 'performance_schema', 'sys') ORDERBY COUNT_STAR DESC LIMIT 10;
-- 找出从未使用过的索引 SELECT CONCAT(object_schema, '.', object_name) AS table_name, index_name, COUNT_STAR AS access_count FROM performance_schema.table_io_waits_summary_by_index_usage WHERE object_schema NOTIN ('mysql', 'performance_schema', 'sys') AND index_name ISNOTNULL AND index_name !='PRIMARY' AND COUNT_STAR =0 ORDERBY object_schema, object_name;
-- 生成删除索引的 SQL SELECT CONCAT('ALTER TABLE ', object_schema, '.', object_name, ' DROP INDEX ', index_name, ';') AS drop_sql FROM performance_schema.table_io_waits_summary_by_index_usage WHERE object_schema ='your_database' AND index_name ISNOTNULL AND index_name !='PRIMARY' AND COUNT_STAR =0;
场景 5: 分析内存使用
1 2 3 4 5 6 7 8 9 10 11 12 13
-- 查看哪些查询占用内存最多 SELECT t.processlist_id, t.processlist_user, s.sql_text, ROUND(SUM(m.current_allocated)/1024/1024, 2) AS memory_mb FROM performance_schema.memory_summary_by_thread_by_event_name m JOIN performance_schema.threads t ON m.thread_id = t.thread_id LEFTJOIN performance_schema.events_statements_current s ON t.thread_id = s.thread_id WHERE t.processlist_id ISNOTNULL GROUPBY t.thread_id ORDERBYSUM(m.current_allocated) DESC LIMIT 10;
Performance Schema vs sys Schema
sys Schema 是 MySQL 5.7 引入的一组视图和函数,基于 Performance Schema 提供更友好的查询接口。
-- 检查配置 SELECT*FROM performance_schema.setup_instruments WHERE NAME LIKE'%statement%'; SELECT*FROM performance_schema.setup_consumers;
5. Performance Schema 与 information_schema 的区别
特性
Performance Schema
information_schema
用途
性能监控和诊断
元数据查询
数据来源
运行时收集
数据字典
实时性
实时
实时
性能开销
可控(可配置)
很小
典型表
events_statements_*
TABLES, COLUMNS, INDEXES
监控脚本示例
1. 定期监控慢查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
#!/bin/bash # monitor_slow_queries.sh
mysql -u root -p'password' -e " SELECT NOW() AS check_time, schema_name, LEFT(DIGEST_TEXT, 100) AS sql_preview, COUNT_STAR AS exec_count, TRUNCATE(AVG_TIMER_WAIT/1000000000000, 6) AS avg_time_s FROM performance_schema.events_statements_summary_by_digest WHERE schema_name IS NOT NULL AND AVG_TIMER_WAIT > 1000000000000 ORDER BY AVG_TIMER_WAIT DESC LIMIT 10; " >> /var/log/mysql_slow_queries.log
-- 保存为存储过程 DELIMITER $$ CREATEPROCEDURE check_lock_waits() BEGIN SELECT CONCAT('锁等待检测时间: ', NOW()) AS info;
SELECT w.requesting_thread_id AS waiting_thread, w.blocking_thread_id AS blocking_thread, waiting.processlist_id AS waiting_pid, blocking.processlist_id AS blocking_pid, waiting_stmt.sql_text AS waiting_sql, blocking_stmt.sql_text AS blocking_sql FROM performance_schema.data_lock_waits w JOIN performance_schema.threads waiting ON w.requesting_thread_id = waiting.thread_id JOIN performance_schema.threads blocking ON w.blocking_thread_id = blocking.thread_id LEFTJOIN performance_schema.events_statements_current waiting_stmt ON waiting.thread_id = waiting_stmt.thread_id LEFTJOIN performance_schema.events_statements_current blocking_stmt ON blocking.thread_id = blocking_stmt.thread_id; END$$ DELIMITER ;