mysql性能调优之SQL分析与优化

ops/2025/1/23 20:41:01/

1、查询优化
避免使用SELECT *:尽量只选择需要的列,避免使用SELECT *,以减少数据传输量和处理时间。
合理使用LIMIT:当查询结果集较大时,使用LIMIT限制返回的行数,避免一次性返回大量数据。
优化JOIN和子查询:尽量使用JOIN来代替子查询,因为JOIN通常比子查询更高效。
优化WHERE子句,避免全表扫描:确保WHERE子句中的条件能够使用索引,避免全表扫描。
避免使用OR和NOT IN:这些操作可能会导致全表扫描,影响查询性能。
使用EXPLAIN分析查询:通过EXPLAIN命令查看查询的执行计划,了解MySQL是如何执行查询的,从而找出性能瓶颈。
2、插入、更新和删除优化
批量操作:当需要插入、更新或删除大量数据时,尽量使用批量操作,减少与数据库的交互次数。例如,在插入数据时,使用多条 VALUES 语句一次性插入多行数据。
避免频繁更新索引列:因为每次更新索引列都会导致索引的重新构建,影响性能。如果可能,将经常更新的列放在索引之外
3、案例
SQL优化指的是SQL本身语法没有问题,但是有实现相同目的的更好的写法。比如:

使用小表驱动大表;用join改写子查询;or改成union
连接查询中,尽量减少驱动表的扇出(记录数),访问被驱动表的成本要尽量低,尽量在被驱动表的连接列上建立索引,降低访问成本;被驱动表的连接列最好是该表的主键或者是唯一二级索引列,这样被驱动表的成本会降到更低
大偏移量的limit,先过滤再排序
针对最后一条举个简单的例子,下面两条语句能实现同样的目的,但是第二条的执行效率比第一条执行效率要高得多(存储引擎使用的是InnoDB),大家感受一下:

-- 1. 大偏移量的查询
sql>mysql> SELECT * FROM user_innodb LIMIT 9000000,10;
Empty set (8.18 sec)

-- 2.先过滤ID(因为ID使用的是索引),再limit
sql>mysql> SELECT * FROM user_innodb WHERE id > 9000000 LIMIT 10;
Empty set (0.02 sec)

索引优化
1、选择合适的索引列
创建合适的索引:根据查询条件创建合适的索引,可以显著提高查询效率。经常在 WHERE、JOIN 和 ORDER BY 子句中使用的列应该创建索引。
避免过多索引:虽然索引可以提高查询效率,但过多的索引会占用磁盘空间,并降低写入性能,同时过多的索引会增加数据插入、更新和删除的成本,因为每次数据变更都需要更新相关的索引。
使用复合索引:对于经常一起查询的列,可以创建复合索引以提高查询速度。
覆盖索引:如果查询的列都在索引中,MySQL可以直接通过索引获取数据,而不需要回表查询,这称为覆盖索引。
避免在数据值分布非常不均匀的列上创建索引:例如,一个列的大部分值都是相同的,索引的效果可能不明显。
使用复合索引:对于经常一起查询的列,可以创建复合索引以提高查询速度。
2、索引类型选择
B - Tree 索引:是 MySQL 中最常用的索引类型,适用于大多数情况,包括等值查询、范围查询和排序操作。
Hash 索引:适用于等值查询,但不支持范围查询和排序操作。在内存表(MEMORY 存储引擎)中,Hash 索引可以提供非常快的查询速度。
3、慢查询
慢查询就是执行地很慢的查询(这句话说得跟废话似的。。。),只有知道MySQL中有哪些慢查询我们才能针对性地进行优化。

因为开启慢查询日志是有性能代价的,因此MySQL默认是关闭慢查询日志功能,使用以下命令查看当前慢查询状态

sql>mysql> show variables like 'slow_query%';
+---------------------+--------------------------------------+
| Variable_name       | Value                                |
+---------------------+--------------------------------------+
| slow_query_log      | OFF                                  |
| slow_query_log_file | /var/lib/sql>mysql/9e74f9251f6c-slow.log |
+---------------------+--------------------------------------+
2 rows in set (0.00 sec)

slow_query_log表示当前慢查询日志是否开启,slow_query_log_file表示慢查询日志的保存位置。

除了上面两个变量,我们还需要确定“慢”的指标是什么,即执行超过多长时间才算是慢查询,默认是10S,如果改成0的话就是记录所有的SQL。

sql>mysql> show variables like '%long_query%';
+-----------------+-----------+
| Variable_name   | Value     |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set (0.00 sec)

1、打开慢日志
有两种打开慢日志的方式

修改配置文件my.cnf
此种修改方式系统重启后依然有效
# 是否开启慢查询日志
slow_query_log=ON

long_query_time=2
slow_query_log_file=/var/lib/sql>mysql/slow.log

动态修改参数(重启后失效)
sql>mysql> set @@global.slow_query_log=1;
Query OK, 0 rows affected (0.06 sec)

sql>mysql> set @@global.long_query_time=2;
Query OK, 0 rows affected (0.00 sec)

2、慢日志分析
mySQL不仅为我们保存了慢日志文件,还为我们提供了慢日志查询的工具sql>mysqldumpslow,为了演示这个工具,我们先构造一条慢查询:

sql>mysql> SELECT sleep(5);
1
然后我们查询用时最多的1条慢查询:

[root@aaa ~]# sql>mysqldumpslow -s t -t 1 -g 'select' /var/lib/sql>mysql/aaa-slow.log

Reading sql>mysql slow query log from /var/lib/sql>mysql/aaa-slow.log
Count: 1  Time=10.00s (10s)  Lock=0.00s (0s)  Rows=1.0 (1), root[root]@localhost
  SELECT sleep(N)

其中,

Count:表示这个SQL执行的次数
Time:表示执行的时间,括号中的是累积时间
Locks:表示锁定的时间,括号中的是累积时间
Rows:表示返回的记录数,括号中的是累积数
更多关于sql>mysqldumpslow的使用方式,可以查阅官方文档,或者执行sql>mysqldumpslow --help寻求帮助。
4、查看运行中的线程
我们可以运行show full processlist查看MySQL中运行的所有线程,查看其状态和运行时间,找到不顺眼的,直接kill。

其中,

Id:线程的唯一标志,可以使用Id杀死指定线程
User:启动这个线程的用户,普通账户只能查看自己的线程
Host:哪个ip和端口发起的连接
db:线程操作的数据库
Command:线程的命令
Time:操作持续时间,单位秒
State:线程的状态
Info:SQL语句的前100个字符
5、查看服务器运行状态
使用SHOW STATUS查看MySQL服务器的运行状态,有session和global两种作用域,一般使用like+通配符进行过滤。

-- 查看select的次数
sql>mysql> SHOW GLOBAL STATUS LIKE 'com_select';
+---------------+--------+
| Variable_name | Value  |
+---------------+--------+
| Com_select    | 168241 |
+---------------+--------+
1 row in set (0.05 sec)

6、查看存储引擎运行信息
SHOW ENGINE用来展示存储引擎的当前运行信息,包括事务持有的表锁、行锁信息;事务的锁等待情况;线程信号量等待;文件IO请求;Buffer pool统计信息等等数据。
例如:


上面这条语句可以展示innodb存储引擎的当前运行的各种信息,大家可以据此找到MySQL当前的问题,限于篇幅不在此意义说明其中信息的含义,大家只要知道MySQL提供了这样一个监控工具就行了,等到需要的时候再来用就好。

7、EXPLAIN执行计划
通过慢查询日志我们可以知道哪些SQL语句执行慢了,可是为什么慢?慢在哪里呢?

MySQL提供了一个执行计划的查询命令EXPLAIN,通过此命令我们可以查看SQL执行的计划,所谓执行计划就是:优化器会不会优化我们自己书写的SQL语句(比如外连接改内连接查询,子查询优化为连接查询…)、优化器针对此条SQL的执行对哪些索引进行了成本估算,并最终决定采用哪个索引(或者最终选择不用索引,而是全表扫描)、优化器对单表执行的策略是什么,等等等等。

EXPLAIN在MySQL5.6.3之后也可以针对UPDATE、DELETE和INSERT语句进行分析,但是通常情况下我们还是用在SELECT查询上。

8、硬件优化
足够的内存:MySQL使用缓冲区来缓存数据和索引文件,因此需要足够的RAM来确保所有数据都能被缓存。
快速的存储设备:使用更快的存储设备(如SSD)可以提高IO吞吐量,减少延迟。
使用RAID:将数据分布在多个磁盘上以提高磁盘读写性能和可靠性。
9、业务优化
严格来说,业务方面的优化已经不算是MySQL调优的手段了,但是业务的优化却能非常有效地减轻数据库访问压力,这方面一个典型例子就是淘宝,下面举几个简单例子给大家提供一下思路:

以往都是双11当晚开始买买买的模式,最近几年双11的预售战线越拉越长,提前半个多月就开始了,而且各种定金红包模式丛出不穷,这种方式叫做预售分流。这样做可以分流客户的服务请求,不必等到双十一的凌晨一股脑地集体下单;
双十一的凌晨你或许想查询当天之外的订单,但是却查询失败;甚至支付宝里的小鸡的口粮都被延迟发放了,这是一种降级策略,集结不重要的服务的计算资源,用来保证当前最核心的业务;
双十一的时候支付宝极力推荐使用花呗支付,而不是银行卡支付,虽然一部分考量是提高软件粘性,但是另一方面,使用余额宝实际使用的阿里内部服务器,访问速度快,而使用银行卡,需要调用银行接口,相比之下操作要慢了许多。


http://www.ppmy.cn/ops/152558.html

相关文章

STM32 FreeRTOS软件定时器

软件定时器的简介 FreeRTOS 中的软件定时器是一种轻量级的时间管理工具,用于在任务中创建和管理定时器。软件定时器是基于FreeRTOS 内核提供的时间管理功能实现的,允许开发者创建、启动、停止、删除和管理定时器,从而实现在任务中对时间的灵…

数据清洗新利器:自动化数据清洗工具的探秘

友友们好! 我的新专栏《Python进阶》正式启动啦!这是一个专为那些渴望提升Python技能的朋友们量身打造的专栏,无论你是已经有一定基础的开发者,还是希望深入挖掘Python潜力的爱好者,这里都将是你不可错过的宝藏。 在这个专栏中,你将会找到: ● 深入解析:每一篇文章都将…

C# HTTP/HTTPS 请求测试小工具

这是一个使用 C# 语言开发的实用小工具,旨在帮助用户轻松测试 HTTP 和 HTTPS 请求。 该工具可以发送各种 HTTP 和 HTTPS 请求,包括但不限于 GET、POST、PUT、DELETE 等常见的请求类型。通过简洁明了的界面或命令行操作,用户可以方便地输入目…

Golang笔记——GPM调度器

大家好,这里是Good Note,关注 公主号:Goodnote,专栏文章私信限时Free。本文详细介绍Golang的GPM调度器,包括底层源码及其实现,以及一些相关的补充知识。 文章目录 前情提要并发与并行并行 (Parallel)并发 (…

Python毕业设计选题:基于django+vue的智能租房系统的设计与实现

开发语言:Python框架:djangoPython版本:python3.7.7数据库:mysql 5.7数据库工具:Navicat11开发软件:PyCharm 系统展示 租客注册 添加租客界面 租客管理 房屋类型管理 房屋信息管理 系统管理 摘要 本文首…

数据结构基础之《(15)—排序算法小结》

一、排序算法的稳定性 1、稳定性是指同样大小的样本再排序之后不会改变相对次序 2、对基础类型来说,稳定性毫无意义 比如:3和3没有区别。《潜伏》里说同样两个一百元大钞,你能告诉我哪一个是高尚的那一个是龌龊的么 3、对非基础类型来说&a…

vim练级攻略(精简版)

vim推荐配置: curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh && bash ./install.sh 0. 规定 Ctrl-λ 等价于 <C-λ> :command 等价于 :command <回车> n 等价于 数字 blank字符 等价于 空格&#xff0c;tab&am…

web路径问题和会话技术(Cookie和Session)

一.Base 1.base介绍①base是HTMl语言的基准网址标签,是一个单标签,位于网页头部文件的head标签内②一个页面最多使用一个base元素,用来提供一个指定的默认目标,是一种表达路径和连接网址的标记③常见的url路径分别有相对路径和绝对路径,如果base标签指定了目标,浏览器将通过这个…