简介:MySQL通过Performance Schema 监控索引,查询索引使用统计
当Oracle用户迁移到MySQL时,常提出的问题是:如何实现类似ALTER INDEX ... MONITORING USAGE的索引监控能力?本文将通过MySQL 8.0的性能监控体系,完整解析索引使用追踪的解决方案。
Oracle索引监控机制
MySQL替代方案
-- 验证性能模式状态
SHOW VARIABLES LIKE 'performance_schema';
-- 若未启用需在my.cnf配置
[mysqld]
performance_schema=ON
performance_schema.table_io_waits_summary_by_index_usage 关键字段:
字段名 | 数据类型 | 描述 |
OBJECT_SCHEMA | varchar | 数据库名 |
OBJECT_NAME | varchar | 表名 |
INDEX_NAME | varchar | 索引名(NULL表示全表扫描) |
COUNT_READ | bigint | 索引读取次数 |
COUNT_WRITE | bigint | 索引写入次数 |
COUNT_FETCH | bigint | 索引数据检索次数 |
-- 基础监控查询
SELECT
OBJECT_SCHEMA AS `数据库`,
OBJECT_NAME AS `表名`,
INDEX_NAME AS `索引`,
COUNT_READ + COUNT_WRITE AS `总操作量`,
COUNT_READ AS `读取次数`,
COUNT_WRITE AS `写入次数`,
COUNT_STAR AS `总触发次数`
FROM
performance_schema.table_io_waits_summary_by_index_usage
WHERE
INDEX_NAME IS NOT NULL
AND OBJECT_SCHEMA = 'your_database'
ORDER BY
COUNT_READ + COUNT_WRITE DESC
LIMIT 10;
-- 高级联合分析(关联INFORMATION_SCHEMA)
SELECT
s.TABLE_NAME,
s.INDEX_NAME,
GROUP_CONCAT(s.COLUMN_NAME ORDER BY s.SEQ_IN_INDEX) AS `索引列顺序`,
p.COUNT_READ,
p.COUNT_WRITE,
STATS.STAT_VALUE AS `索引基数`
FROM
INFORMATION_SCHEMA.STATISTICS s
JOIN
performance_schema.table_io_waits_summary_by_index_usage p
ON s.TABLE_NAME = p.OBJECT_NAME
AND s.INDEX_NAME = p.INDEX_NAME
JOIN
mysql.innodb_index_stats STATS
ON s.TABLE_NAME = STATS.table_name
AND s.INDEX_NAME = STATS.index_name
WHERE
s.TABLE_SCHEMA = 'your_database'
GROUP BY
s.TABLE_NAME, s.INDEX_NAME;
推荐配置Prometheus + Grafana监控体系,抓取指标示例:
- name: mysql_index_usage
metrics_path: /sql
static_configs:
- targets: ['localhost:3306']
params:
query:
- >
SELECT
NOW() as timestamp,
OBJECT_SCHEMA,
OBJECT_NAME,
INDEX_NAME,
COUNT_READ,
COUNT_WRITE
FROM
performance_schema.table_io_waits_summary_by_index_usage
4.1 Sys Schema快捷查询
-- 索引使用统计视图
SELECT *
FROM sys.schema_index_statistics
WHERE table_schema = 'your_database';
-- 索引使用效率分析
SELECT
table_name,
index_name,
rows_selected / (rows_read + 1) AS select_efficiency
FROM sys.schema_index_statistics
WHERE table_schema = 'your_database';
-- 启用配置
SET GLOBAL slow_query_log = 1;
SET GLOBAL log_queries_not_using_indexes = 1;
SET GLOBAL long_query_time = 1;
-- 日志分析示例
pt-index-usage /var/lib/mysql/slow.log
-- 定期重置统计(建议每日凌晨执行)
CREATE EVENT reset_index_stats
ON SCHEDULE EVERY 1 DAY
STARTS CURRENT_TIMESTAMP
DO
TRUNCATE performance_schema.table_io_waits_summary_by_index_usage;
-- 查看隐藏的GEN_CLUST_INDEX
SHOW VARIABLES LIKE 'show_gipk%';
-- 8.0.30+版本可通过以下设置隐藏
SET PERSIST show_gipk_in_create_table_and_information_schema = OFF;
UPDATE performance_schema.setup_consumers
SET ENABLED = 'NO'
WHERE NAME LIKE '%history%';
graph TD
A[开始监控] --> B{索引使用率>阈值?}
B -->|是| C[保留索引]
B -->|否| D{索引是否唯一?
D -->|是| E[必须保留]
D -->|否| F{数据更新频率
F -->|低频| G[考虑删除]
F -->|高频| H[评估查询模式]
H --> I[是否用于排序/分组?]
I -->|是| C
I -->|否| G
-- 长期未使用索引清单
SELECT
t.TABLE_SCHEMA,
t.TABLE_NAME,
s.INDEX_NAME,
s.CARDINALITY,
DATEDIFF(NOW(), t.UPDATE_TIME) AS days_unused
FROM
INFORMATION_SCHEMA.TABLES t
JOIN
INFORMATION_SCHEMA.STATISTICS s
ON t.TABLE_NAME = s.TABLE_NAME
LEFT JOIN
performance_schema.table_io_waits_summary_by_index_usage u
ON s.INDEX_NAME = u.INDEX_NAME
WHERE
u.COUNT_READ IS NULL
AND u.COUNT_WRITE IS NULL
AND t.TABLE_SCHEMA = 'your_db';
有遗漏或者不对的可以在我的公众号留言哦