MySql的性能优化指的是在不影响系统能正确运行的前提下,运行速度更快,完成特定功能所需的时间更短。
我们可以通过某些有效的方法来提高 MySQL 数据库的性能:
优化方面 | 核心策略 | 具体方法与示例 |
---|---|---|
数据库设计 | 平衡规范与效率 选择合适的数据类型 | 规范化: 消除冗余,保证数据一致性 (如:将用户地址拆分成独立表)。 反规范化: 减少JOIN,提升读性能 (如:在用户表中直接存储常用地址字段)。 使用 INT 而非 BIGINT ; 使用 VARCHAR(100) 而非 TEXT ,以节省空间并提升效率。 |
查询优化 | 避免低效操作 | 使用 EXPLAIN 分析执行计划,避免全表扫描。避免 SELECT *, 仅查询所需字段。 使用 LIMIT 限制返回行数。 |
简化复杂操作 | 减少不必要的 JOIN ; 考虑在应用层进行数据聚合。 | |
索引优化 | 有效创建索引 | 为高频查询条件(WHERE )、连接字段(JOIN )、排序字段(ORDER BY )创建索引。使用复合索引匹配多列查询。 |
避免索引滥用 | 避免为不常用或重复度低的列创建索引,以减少写操作开销。 使用覆盖索引 (索引包含所有查询字段) 避免回表,极大提升速度。 | |
配置与硬件 | 调整内存设置 | 设置合理的 innodb_buffer_pool_size (通常为物理内存的70-80%),将热点数据缓存在内存中。 |
升级硬件基础设施 | 使用 SSD硬盘 提升I/O速度; 增加内存容量; 升级CPU。 | |
架构扩展 | 数据分片 | 分库分表: 对超大规模数据进行水平拆分(按范围或哈希)或垂直拆分(按业务模块),分散负载。 |
读写分离 | 配置主从复制,主库处理写操作,多个从库处理读操作,并通过负载均衡分发请求。 | |
日常维护 | 定期清理与优化 | 定期清理无用数据,缩减表体积。 定期执行 OPTIMIZE TABLE 或 ANALYZE TABLE 来整理碎片和更新统计信息,帮助优化器选择最佳执行计划。 |
MySQL数据库的性能特质,在低负载环境下往往难以被准确评估和观测。其真正的性能瓶颈、扩展性以及稳定性,只有在长时间、高并发、大数据量的生产级负载下才会充分暴露。当数千甚至上万用户同时访问一个网站时,每个点击、每次浏览都意味着向MySQL数据库发起查询、插入或更新操作。如果数据库性能不佳,大量并发请求会迅速耗尽数据库连接池,导致新的用户请求被拒绝,出现“无法连接数据库”的错误。同时,频繁的写操作会造成严重的锁竞争,更新订单状态或库存时会发生阻塞,使系统陷入停滞。而最直接影响用户体验的是查询速度。如果用户搜索一个商品或查看个人订单需要等待超过2-3秒,几乎一半的人会选择离开。缓慢的查询响应会让页面加载变得卡顿,直接导致用户流失和交易失败。因此,在高并发场景下,数据库性能直接决定了网站能否正常运营和用户体验的好坏。
因此,系统性地提升MySQL数据库性能是一项多维度的工程任务,其核心目标在于精准定位系统瓶颈,并通过体系化的优化策略实现整体性能提升。这要求我们不仅需要优化数据库本身的软硬件配置和参数调优,更要从数据模型设计的源头确保架构合理性,从而在显著提升用户操作响应速度的同时,高效利用系统资源,以支撑更大规模的业务负荷。
具体而言,优化工作需根据实际负载类型针对性展开。若数据库负载以大量查询操作为主,则应将优化重点置于SQL语句层面,通过分析和重写高时间复杂度的查询、引入恰当的索引策略,来降低单次查询的资源消耗,从而提升整体吞吐量。所以我们需要找到效率低下的SQL。
我们可以通过以下两种方式精准定位效率低下的SQL:
1. 使用 SHOW STATUS 命令
数据库管理员可以通过执行 SHOW STATUS语句来获取 MySQL 数据库的一系列内部性能计数器和状态变量。
其语法形式如下:
SHOW STATUS LIKE 'value';
其中,value最主要的参数有:
类别 | 变量名 | 描述 | 解读与用途 |
---|---|---|---|
连接与线程 | Threads_connected | 当前打开的连接数。 | 监控数据库负载和连接池大小是否合理。 |
Threads_running | 当前正在执行的连接数。 | 如果持续接近 max_connections ,说明服务器繁忙或存在瓶颈。 | |
Threads_created | 服务器启动后为处理连接而创建的线程总数。 | 如果值很大,表明应增大 thread_cache_size 以节省创建线程的开销。 | |
Aborted_connects | 尝试连接到数据库失败的次数。 | 可用于检查是否有网络问题或错误的连接参数。 | |
Max_used_connections | 服务器启动后同时使用的最大连接数。 | 用于指导 max_connections 的设置,应留有余量。 | |
查询相关 | Questions | 服务器启动以来客户端发送给服务器的语句总数。 | 监控数据库总的请求压力。 |
Queries | 服务器启动以来执行的语句总数(包括存储过程中的语句)。 | 类似于 Questions ,但计数范围更广。 | |
Com_select | SELECT 语句的执行次数。 | 了解读操作的频率。 | |
Com_insert | INSERT 语句的执行次数。 | 了解写操作的频率。 | |
Com_update | UPDATE 语句的执行次数。 | 了解写操作的频率。 | |
Com_delete | DELETE 语句的执行次数。 | 了解写操作的频率。 | |
Slow_queries | 执行时间超过 long_query_time 秒的查询数量。 | 关键指标。值持续增长意味着有查询需要优化。 | |
InnoDB 存储引擎 | Innodb_rows_read | 从InnoDB表中读取的行数。 | 评估数据库的总读取量。 |
Innodb_rows_updated | InnoDB表中更新的行数。 | 评估数据库的总写入量。 | |
Innodb_rows_deleted | InnoDB表中删除的行数。 | 评估数据库的总写入量。 | |
Innodb_rows_inserted | InnoDB表中插入的行数。 | 评估数据库的总写入量。 | |
Innodb_buffer_pool_reads | 从物理磁盘读取页面的请求数。 | 关键指标。值高说明缓冲池太小或查询未有效利用缓存。 | |
Innodb_buffer_pool_read_requests | 向缓冲池发起的逻辑读请求数。 | 与 ...reads 对比计算缓存命中率。 | |
缓存与临时表 | Key_reads | 从磁盘物理读取MyISAM索引块的次数。 | 对于MyISAM表,值高说明 key_buffer_size 设置太小。 |
Key_read_requests | 向MyISAM键缓存发起的读请求数。 | 用于计算MyISAM键缓存命中率。 | |
Created_tmp_disk_tables | 服务器创建磁盘临时表的次数。 | 关键指标。值高意味着需要优化查询或增加 tmp_table_size 。 | |
Created_tmp_tables | 服务器创建临时表的总次数(包括内存和磁盘)。 | 用于计算磁盘临时表占比。 | |
Qcache_hits | 查询缓存命中的次数。 | (注:MySQL 8.0已移除查询缓存) 用于评估查询缓存的效益。 | |
Qcache_inserts | 被加入到查询缓存的查询数量。 | (注:MySQL 8.0已移除查询缓存) |
举一个最简单的例子,当我们需要查询 MySQL 服务器的连接次数,我们可以这样操作:
进入到MySQL Command Line Client:
输入:
SHOW STATUS LIKE 'Connections';
结果:
意义:自从MySQL连接以来,一共尝试连接过12次.(提示:在默认界面第3行-Your MySQL connection id is 12-这里可以看到连接次数)
2. 使用慢查询日志
通过慢查询日志定位那些执行效率较低的 SQL 语句,然后针对慢查询语句进行表结构优化或者查询语句优化。
一个简单的例子教会你通过慢查询日志定位执行效率底的 SQL 语句:(以我的电脑为例)
2.1 开启慢查询日志 , 配置样例:
找到并复制这个路径:C:\ProgramData\MySQL\MySQL Server 8.0\my.ini(一般情况下都是这个路径 主要是找到配置文件my.ini)
然后管理员模式启动记事本进行修改
找到[mysqld]
2.2 修改参数(添加以下参数)
# 启用慢查询日志功能 (1=ON, 0=OFF) slow_query_log = 1 # 指定慢查询日志文件的存储路径和文件名 slow_query_log_file = /var/log/mysql/mysql-slow.log # 定义“慢”的阈值,单位是秒。执行时间超过此值的SQL将被记录 long_query_time = 5 # 通常先设置为5秒,根据实际情况调整
2.3 重启mysql
win+x 然后按A键进入PowerShell进行重启操作
2.4检查是否开启慢查询
输入:
SHOW VARIABLES LIKE 'slow_query_log';
结果:显示慢查询日志已打开
3.1 临时修改时间阈值
输入:
SET SESSION long_query_time = 1;
结果:设置为1秒
3.2 执行一条慢的SQL
输入:
SELECT SLEEP(8);
结果:超过1秒 被记录
3.3 执行一条快的SQL
输入:
SELECT SLEEP(0.1);
结果:未超过1秒 不会被记录
4.1 找到 C:\ProgramData\MySQL\MySQL Server 8.0\Data\DESKTOP-BO8KI50-slow.log
4.2 在慢查询日志里我们可以看到:
解读:查询到我们超过1秒的SQL语句及其相关信息
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程