云数据库 · RDS

先找瓶颈,再动手改,别凭感觉加索引

我们做过的性能优化里,超过一半的收益来自三五条慢查询和缺失的索引,跟实例规格无关。

调优五步法

  1. 01

    建立基线

    Performance Insights 看 DB Load 按等待事件分解,明确到底是 CPU、IO 还是锁在拖后腿。

    交付物:等待事件分布图、Top SQL 清单、负载基线

    1-2 天

  2. 02

    定位 Top SQL

    按总耗时排序而不是单次耗时。一条 50ms 但每秒执行 2000 次的查询,比一条 3 秒的报表查询影响大得多。

    交付物:按总耗时排序的 SQL 清单、执行计划分析

    2-3 天

  3. 03

    索引与查询改写

    补复合索引、消除全表扫描、拆分大事务、避免 SELECT *。改动先在只读副本上验证执行计划。

    交付物:索引变更清单、SQL 改写方案、回归测试结果

    1-2 周

  4. 04

    参数与连接调优

    调整 buffer pool、连接数上限、超时参数;引入连接池或 RDS Proxy 减少连接开销。

    交付物:参数组变更、连接池配置、压测对比

    3-5 天

  5. 05

    读写分离与缓存

    把报表和统计类查询导到只读副本,热点数据放 ElastiCache,从根上减少数据库压力。

    交付物:读写分离方案、缓存策略、命中率监控

    1-3 周

定位 MySQL 慢查询与缺失索引

sql diagnose.sql
-- 1. 按总耗时排序的 Top SQL(需开启 performance_schema)
SELECT
    DIGEST_TEXT                                   AS sql_pattern,
    COUNT_STAR                                    AS exec_count,
    ROUND(SUM_TIMER_WAIT / 1e12, 2)               AS total_sec,
    ROUND(AVG_TIMER_WAIT / 1e9, 2)                AS avg_ms,
    SUM_ROWS_EXAMINED                             AS rows_examined,
    SUM_ROWS_SENT                                 AS rows_sent,
    ROUND(SUM_ROWS_EXAMINED / GREATEST(SUM_ROWS_SENT, 1), 1) AS scan_ratio
FROM performance_schema.events_statements_summary_by_digest
WHERE SCHEMA_NAME NOT IN ('mysql', 'performance_schema', 'sys')
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 20;

-- 2. 全表扫描严重的语句(scan_ratio 越高越可疑)
SELECT
    DIGEST_TEXT,
    COUNT_STAR,
    SUM_NO_INDEX_USED                             AS no_index_count,
    SUM_NO_GOOD_INDEX_USED                        AS bad_index_count
FROM performance_schema.events_statements_summary_by_digest
WHERE SUM_NO_INDEX_USED > 0
ORDER BY SUM_NO_INDEX_USED DESC
LIMIT 20;

-- 3. 从未被使用的索引(可考虑删除,减少写放大)
SELECT
    object_schema, object_name, index_name
FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE index_name IS NOT NULL
  AND index_name <> 'PRIMARY'
  AND count_star = 0
  AND object_schema NOT IN ('mysql', 'performance_schema', 'sys')
ORDER BY object_schema, object_name;

-- 4. 表级 IO 热点
SELECT
    object_schema, object_name,
    count_read, count_write,
    ROUND(sum_timer_read / 1e12, 2)  AS read_sec,
    ROUND(sum_timer_write / 1e12, 2) AS write_sec
FROM performance_schema.table_io_waits_summary_by_table
WHERE object_schema NOT IN ('mysql', 'performance_schema', 'sys')
ORDER BY (sum_timer_read + sum_timer_write) DESC
LIMIT 15;

第三条查询要注意:统计窗口从实例启动开始,刚重启过的实例数据不可信。至少观察一周。

常见等待事件与对策

等待事件含义常见原因对策
CPU计算资源饱和低效查询、缺索引、排序临时表优化 SQL、补索引,最后才考虑升配
io/table/sql/handler表数据读取全表扫描、buffer pool 太小补索引、增大 buffer pool
synch/mutex/innodb内部锁竞争高并发写同一热点行拆分热点、批量合并写、改用队列削峰
lock/table/sql/handler表锁等待长事务、DDL 阻塞缩短事务、DDL 走 gh-ost 或 pt-osc
io/file/innodb/innodb_log_fileredo 日志写入写入量大、IOPS 不足提高卷 IOPS、合并小事务

下一步

把云的复杂度交给我们,你只管做业务

留下需求,沐杉云的解决方案架构师会在一个工作日内联系你,提供免费的现状评估、迁移方案草案与 TCO 测算表。