MySQL调优到底从哪下手?先把参数表和慢查询放一边
数据库开始变慢的时候,很多人第一反应是去看配置文件里的参数。改几个数字重启一下,发现没什么变化。这种情况我见过不少,问题通常不在参数上,而在SQL本身。调优的顺序如果反过来,先动参数再查语句,多半白费功夫。这里把顺序和判断标准说清楚。
先确认瓶颈在数据库,不在别的层
应用响应慢,未必是MySQL的问题。连接池打满、网络抖动、磁盘IO被别人抢走,都会表现成数据库慢。上机器之前先看两个数:SHOW GLOBAL STATUS 里的 Threads_connected 和 Threads_running。前者是总连接数,后者是正在执行的查询数。如果 Threads_running 长期只有个位数,但连接数很高,那瓶颈更可能在应用侧的连接池配置。
再看 SHOW ENGINE INNODB STATUS,看有没有长时间的锁等待。锁等待多,说明事务设计有问题,不是参数能解决的。
这一步花不了十分钟,但能省掉后面瞎调参数的时间。我一般会先做这一步确认,再决定往哪个方向走。
慢查询日志打开之后,重点看扫描行数
慢查询日志默认是关的,先打开。阈值设成1秒比较合适,设0.1秒会刷出一堆正常查询。日志里看什么?不是看执行时间,是看 Rows_examined。一个查询扫了50万行只返回10条,那不管它跑多快,迟早会出问题。
拿这条SQL去跑 EXPLAIN,重点看 type 和 rows 两列。type 出现 ALL 就是全表扫描,出现 index 是扫了整个索引。这两种情况都说明索引没建对。
索引不是越多越好。一张写入频繁的表,索引超过5个就要小心了,每次INSERT都得更新所有索引。索引的取舍标准很简单:这个字段在WHERE里出现的频率高不高,区分度够不够。区分度低的字段,比如性别、状态标记,单独建索引基本没用。
缓冲池给多少,直接决定读性能
innodb_buffer_pool_size 是InnoDB最值得调的一个参数。它决定数据和索引有多少能缓存在内存里。给少了,每次查询都要读磁盘;给多了,系统其他进程没内存用,容易触发swap。
一个常见的配置参考:
- 物理内存16G的独立数据库机器,缓冲池给8G到10G之间
- 如果机器上还跑着Web服务,缓冲池别超过物理内存的50%
- 物理内存64G以上的专用库,可以给到60%左右
调完这个参数需要重启实例。重启前确认一下业务低峰期,别在白天动。
另一个容易被忽略的是 innodb_log_file_size。默认值偏小,写入密集的场景下会频繁刷盘。通常设成1G到2G之间。这个参数改动同样需要重启,而且改之前要先正常关闭实例,否则可能起不来。
至于连接数、查询缓存这些,8.0版本之后查询缓存已经移除了,不用再折腾。连接数max_connections设太大反而危险,每个连接都占内存,设成500到1000之间对多数业务够用。
读写分离和分表之前,先试试加个从库
单机优化到顶之后,下一步是拆。读多写少的业务,加从库做读写分离是最省事的方案。主库负责写,从库负责读,应用层改一下数据源路由就行。
写多的业务,读写分离帮助有限,得考虑分表。分表之前先看单表数据量,通常超过2000万行之后,即使有索引,B+树层数也会增加,查询变慢。分表方案里,按时间分和按业务ID分是两种常见做法,选哪种取决于查询模式。
如果数据库本身压力不算大,但磁盘IO经常跑满,可以考虑把数据目录放到独立磁盘上。数据库和系统盘分开,是成本不高但效果明显的做法。海外业务选服务器时,磁盘类型和IOPS比CPU核数更值得关注。秀米云的马来西亚裸机云 XI 用的是E5-2680v4双路加64G内存,月付159美元,适合中小规模的数据库实例。
调优这件事没有一步到位的方案。先把慢查询日志打开,把扫描行数高的语句找出来加索引,再把缓冲池调到合理区间,多数业务的响应时间能降下来一半以上。如果这三步做完还是慢,再考虑拆库拆表。换我我会按这个顺序来,不会一上来就改参数文件。