MySQL性能提升那些事儿,实操经验和技巧分享,不说废话直接干
- 问答
- 2025-12-25 19:18:01
- 2
MySQL性能提升那些事儿,实操经验和技巧分享 主要来自我在实际项目中的踩坑和填坑经验,以及从像“高性能MySQL”这本书、Percona官网的技术博客、以及公司里几位老DBA的言传身教中学到的东西,我们不扯那些高大上的理论,就直接说怎么干。
先从最立竿见影的SQL优化说起
很多时候,数据库慢,八成是SQL语句写得有问题,我的习惯是,一接到性能问题的反馈,第一个动作就是去查慢查询日志。
-
实操第一步:开启并分析慢查询日志 你得先知道哪些SQL慢,在MySQL的配置文件my.cnf(或my.ini)里加上这几行:
slow_query_log = 1slow_query_log_file = /var/lib/mysql/slow.loglong_query_time = 2# 设置成你觉得慢的阈值,比如2秒,初期可以设小点,比如0.5秒,抓得更多。 重启MySQL后,所有执行时间超过long_query_time的SQL都会被记录到那个文件里,然后就用MySQL自带的mysqldumpslow工具或者用pt-query-digest(Percona Toolkit里的一个神器,强烈建议安装)来分析这个日志文件。pt-query-digest会帮你把类似的SQL归组,告诉你哪条SQL总耗时最长,单次执行最慢,执行次数最多,一目了然。 -
实操第二步:用EXPLAIN揪出元凶 找到嫌疑最重的慢SQL后,别急着改,先把它前面加上
EXPLAIN关键字执行一下。EXPLAIN SELECT * FROM users WHERE name = '张三';,这个命令显示的不是查询结果,而是MySQL的执行计划,你就盯着几个关键列:- type列:这是最重要的,如果看到
ALL,意思是全表扫描,这是最糟糕的情况,说明没用到索引,我们追求的是const(主键或唯一索引)、eq_ref(关联查询时主键或唯一索引)、ref(普通索引)、range(索引范围扫描),起码要优化到range级别。 - key列:显示MySQL实际决定使用的索引,如果这一列是NULL,恭喜你,找到了问题所在——这条SQL没走索引。
- rows列:MySQL预估要扫描多少行数据才能找到结果,这个数字越大,说明越费劲。
- type列:这是最重要的,如果看到
-
实操第三步:建索引,但别乱建 通过EXPLAIN发现没走索引,那就要考虑加索引了,比如上面那个
SELECT * FROM users WHERE name = '张三';,如果name字段没索引,就会全表扫描,这时候可以加一个:ALTER TABLE users ADD INDEX idx_name (name);。 索引不是越多越好,这是我栽过跟头的地方,索引就像书的目录,能加快查询,但会增加写操作(INSERT/UPDATE/DELETE)的负担,因为每次写数据都要更新索引,还会占用更多磁盘空间,所以建索引的原则是:- 只为那些出现在WHERE子句、ORDER BY子句和GROUP BY子句中的列建索引。
- 使用前缀索引:如果字段特别长,比如是一个TEXT类型,没必要对整个字段建索引,可以只索引前一部分字符,比如
ALTER TABLE articles ADD INDEX idx_title (title(50));只对标题的前50个字符建索引,通常也够用了,这个长度需要根据数据分布来权衡。 - 多列索引(联合索引)要注意顺序:有一个口诀叫“最左前缀原则”,比如你建了一个
INDEX idx_age_name (age, name),那么查询条件WHERE age=20、WHERE age=20 AND name='张三'都能用到这个索引,但WHERE name='张三'就用不到,所以要把区分度最高的、最常用的列放在左边。
除了SQL, schema设计也很关键
表结构设计的时候就得想着以后怎么查数据。
- 避免使用NULL:这是我听一位老DBA说的,字段尽量设为
NOT NULL并给默认值(如空字符串、0),因为NULL值会让索引、索引统计和值比较都变得更复杂。 - 选择更小的数据类型:比如能用
TINYINT就不要用INT,能VARCHAR(10)就不要VARCHAR(100),因为数据类型越小,磁盘读写越快,占用的内存也越少,一个数据页能放下的行数就越多,查询效率自然更高。 - 范式与反范式的权衡:教科书教我们数据库要满足第三范式,减少冗余,但在大并发查询的场景下,有时需要适当的反范式设计,用空间换时间,比如一个订单表,需要频繁显示用户姓名,如果每次都去联表查询用户表,开销很大,可以考虑在订单表里冗余一个
user_name字段,这样虽然增加了数据冗余和维护成本(更新用户名时要同时更新订单表),但换来了查询速度的极大提升,这个决策要根据实际业务查询模式来定。
服务器和配置的“后勤”保障
SQL和表结构优化好了,如果服务器配置是瓶颈,也白搭。
- 最重要的配置:缓冲池(InnoDB Buffer Pool) 这个是InnoDB引擎的核心,你可以把它理解成数据库的“内存缓存”,它缓存了表和索引的数据,理想状态下,你应该把整个数据库的热点数据都装进缓冲池里,这样大部分读操作就直接在内存里完成了,飞快,通过
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';查看当前大小,一般建议在机器物理内存的60%-80%之间,比如你机器有16G内存,可以设置成10G-12G,改完配置要重启。 - 连接数:
max_connections参数控制最大连接数,如果应用有高并发请求,默认值可能不够,会导致“Too many connections”错误,但也不能设得太大,因为每个连接都会占用一定内存。 - 监控是关键:不能瞎优化,要习惯使用
SHOW GLOBAL STATUS和SHOW ENGINE INNODB STATUS这些命令来查看数据库的运行状态,比如当前连接数、缓冲池命中率(这个非常重要,命中率低说明缓冲池大小可能不够)、锁等待情况等,或者用一些图形化的监控工具,比如Prometheus+Grafana,更直观。
最后总结一下我的核心经验:
- 先诊断,后开药:慢查询日志和EXPLAIN是你的听诊器和X光机。
- 索引是良药,但过量是毒药:精准地为高频查询创建必要的索引。
- 设计表结构时就要考虑怎么取数据,好的设计是成功的一半。
- 给数据库足够的内存(主要是Buffer Pool),这是最直接有效的硬件投资。
- 监控要常态化,不能等出问题了才去看。
这些东西都是实打实踩坑踩出来的,照着做,大部分常见的MySQL性能问题都能解决个七八成。

本文由盈壮于2025-12-25发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:http://waw.haoid.cn/wenda/68338.html
