先说索引这玩意儿。很多新手以为建个索引就能起飞,结果乱建一通反而更慢。比如在性别字段上建索引,值就"男""女"两种,索引效率低得可怜。最好是选区分度高的字段,比如用户ID或者订单号。复合索引的顺序更是关键------如果把范围查询的字段放前面,等于白建。曾经见过有人把时间范围字段放在复合索引第一位,后面跟状态字段,结果查询时索引压根没用上。正确姿势是把等值查询字段放前面,比如,索引就该是。另外别忘了索引也是有代价的,写操作时维护索引会拖慢速度,所以大表加索引最好在业务低峰期操作。
查询语句的坑也不少。有人爱写,看似省事,实际可能拖垮整个库。我遇到过最离谱的案例是某财务系统用查流水表,结果包含十几个 TEXT 字段,网络传输直接爆内存。更隐蔽的是在WHERE子句里对字段做运算,比如,导致索引失效。应该改成。子查询也是个性能杀手,特别是关联子查询,每处理外层一条记录就要执行一次内层查询。能转成JOIN就尽量转,但要注意JOIN的驱动表选择,小表驱动大表是基本原则。
配置参数调优这块,老司机和新手的差距就出来了。默认的通常只设128M,对于现代服务器根本不够看。建议设到物理内存的70%左右,让热点数据尽量留在内存。但也不是越大越好,曾经有同事设到32G导致系统OOM。连接数别盲目调高,否则连接数上去了,每个连接抢不到CPU反而更糟。事务隔离级别推荐用REPEATABLE-READ,但要注意间隙锁可能引起的死锁问题。还有个容易忽略的参数是,遇到复杂排序分组时,临时表太小时会写磁盘,调到64M能明显改善。
慢查询日志必须常态化开启,但别光盯着执行时间。有一次发现个0.8秒的查询看似正常,实际上每分钟执行上千次,累计消耗比单个10秒的查询还可怕。用pt-query-digest工具分析慢日志时,要重点关注Query_time分布和Lock_time。有个经典案例:某电商平台促销时数据库卡顿,最后发现是某个订单统计SQL锁住了主键索引,导致后续插入全阻塞。通过show processlist看到大量"Waiting for table metadata lock",才定位到有未提交的事务长期持有元数据锁。
硬件层面的优化往往立竿见影。SSD替换机械盘能让随机IO性能提升百倍,但要注意RAID卡缓存策略。有次给客户换完SSD反而变慢,最后发现是RAID卡写策略设成了Write-Through。内存容量够大的话,可以把整库热数据装进内存,但需要监控buffer pool命中率,低于95%就要考虑扩容。云数据库现在流行读写分离,不过从库同步延迟可能达到秒级,业务代码要能容忍旧数据。分库分表是终极武器,但建议单表超过500万行再考虑,否则管理成本远大于收益。
最后提醒个反直觉的现象:有时候优化过头反而坏事。见过团队把每个查询都优化到毫秒级,结果高峰期连接数暴涨,上下文切换开销把系统压垮。保持适度冗余其实更稳健,就像高速公路不能全部设计成最短路径。MySQL性能优化没有银弹,关键要建立全链路监控体系,从SQL解析到磁盘IO每个环节都埋点。真正的高手不是能写出最快的SQL,而是能让系统在业务增长时依然保持可控的延迟。下次遇到性能问题,建议先拉上运维和开发一起看监控图表,比盲目调参有效得多。