不允许你不知道的 MySQL 优化实战(一)

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: 不允许你不知道的 MySQL 优化实战(一)

文章目录

1、查询SQL尽量不要使用select *,而是select具体字段。

2、如果知道查询结果只有一条或者只要最大/最小一条记录,建议用limit 1

3、应尽量避免在where子句中使用or来连接条件

4、优化limit分页

5、优化你的like语句

6、使用where条件限定要查询的数据,避免返回多余的行

7、尽量避免在索引列上使用mysql的内置函数

8、应尽量避免在where子句中对字段进行表达式操作,这将导致系统放弃使用索引而进行全表扫

9、Inner join 、left join、right join,优先使用Inner join,如果是left join,左边表结果尽量小

10、应尽量避免在where子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。






多余的话就不说了,直接上菜!

微信截图_20231016162204.png

1、查询SQL尽量不要使用select *,而是select具体字段。

反例子:

select * from employee;

正例子:

select id,name from employee;

理由:

  • 只取需要的字段,节省资源、减少网络开销。
  • select * 进行查询时,很可能就不会使用到覆盖索引了,就会造成回表查询。


2、如果知道查询结果只有一条或者只要最大/最小一条记录,建议用limit 1

假设现在有employee员工表,要找出一个名字叫jay的人.

CREATE TABLE `employee` (  `id` int(11) NOT NULL,  `name` varchar(255) DEFAULT NULL,  `age` int(11) DEFAULT NULL,  `date` datetime DEFAULT NULL,  `sex` int(1) DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

反例:

select id,name from employee where name='jay'

正例

select id,name from employee where name='jay' limit 1;

理由:


加上limit 1后,只要找到了对应的一条记录,就不会继续向下扫描了,效率将会大大提高。

当然,如果name是唯一索引的话,是不必要加上limit 1了,因为limit的存在主要就是为了防止全表扫描,从而提高性能,如果一个语句本身可以预知不用全表扫描,有没有limit ,性能的差别并不大。


3、应尽量避免在where子句中使用or来连接条件

新建一个user表,它有一个普通索引userId,表结构如下:

CREATE TABLE `user` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `userId` int(11) NOT NULL,  `age` int(11) NOT NULL,  `name` varchar(255) NOT NULL,  PRIMARY KEY (`id`),  KEY `idx_userId` (`userId`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;

假设现在需要查询userid为1或者年龄为18岁的用户,很容易有以下SQL

反例:

select * from user where userid=1 or age =18

正例:

//使用union allselect * from user where userid=1 union allselect * from user where age = 18
//或者分开两条sql写:select * from user where userid=1select * from user where age = 18

理由:


使用or可能会使索引失效,从而全表扫描。

对于or+没有索引的age这种情况,假设它走了userId的索引,但是走到age查询条件时,它还得全表扫描,也就是需要三步过程:全表扫描+索引扫描+合并如果它一开始就走全表扫描,直接一遍扫描就完事。mysql是有优化器的,处于效率与成本考虑,遇到or条件,索引可能失效,看起来也合情合理。



4、优化limit分页

我们日常做分页需求时,一般会用 limit 实现,但是当偏移量特别大的时候,查询效率就变得低下。


反例:

select id,name,age from employee limit 10000,10

正例:

//方案一 :返回上次查询的最大记录(偏移量)select id,name from employee where id>10000 limit 10.
//方案二:order by + 索引select id,name from employee order by id  limit 10000,10
//方案三:在业务允许的情况下限制页数:

理由:


当偏移量最大的时候,查询效率就会越低,因为Mysql并非是跳过偏移量直接去取后面的数据,而是先把偏移量+要取的条数,然后再把前面偏移量这一段的数据抛弃掉再返回的。

如果使用优化方案一,返回上次最大查询记录(偏移量),这样可以跳过偏移量,效率提升不少。

方案二使用order by+索引,也是可以提高查询效率的。

方案三的话,建议跟业务讨论,有没有必要查这么后的分页啦。因为绝大多数用户都不会往后翻太多页。


5、优化你的like语句

日常开发中,如果用到模糊关键字查询,很容易想到like,但是like很可能让你的索引失效。


反例:

select userId,name from user where userId like '%123';

正例:

select userId,name from user where userId like '123%';

理由:

  • 把%放前面,并不走索引,如下:

微信截图_20231016162647.png

  • 把% 放关键字后面,还是会走索引的。如下 :
  • 微信截图_20231016162657.png

6、使用where条件限定要查询的数据,避免返回多余的行

假设业务场景是这样:查询某个用户是否是会员。

Java 代码

反例:

List<Long> userIds = sqlMap.queryList("select userId from user where isVip=1");
boolean isVip = userIds.contains(userId);

正例:

Long userId = sqlMap.queryObject("select userId from user where userId='userId' and isVip='1' ")
boolean isVip = userId!=null;

理由:

  • 需要什么数据,就去查什么数据,避免返回不必要的数据,节省开销。


7、尽量避免在索引列上使用mysql的内置函数

业务需求:查询最近七天内登陆过的用户(假设loginTime加了索引)

反例:

select userId,loginTime from loginuser where Date_ADD(loginTime,Interval 7 DAY) >=now();

正例:

explain  select userId,loginTime from loginuser where  loginTime >= Date_ADD(NOW(),INTERVAL - 7 DAY);

理由:

  • 索引列上使用mysql的内置函数,索引失效
  • image.png
  • 如果索引列不加内置函数,索引还是会走的。
  • 微信截图_20231016162910.png

8、应尽量避免在where子句中对字段进行表达式操作,这将导致系统放弃使用索引而进行全表扫

反例:

select * from user where age-1 =10;

正例:

select * from user where age =11;

理由:

  • 虽然age加了索引,但是因为对它进行运算,索引直接迷路了。。
  • 微信截图_20231016163100.png

9、Inner join 、left join、right join,优先使用Inner join,如果是left join,左边表结果尽量小

Inner join 内连接,在两张表进行连接查询时,只保留两张表中完全匹配的结果集

left join 在两张表进行连接查询时,会返回左表所有的行,即使在右表中没有匹配的记录。

right join 在两张表进行连接查询时,会返回右表所有的行,即使在左表中没有匹配的记录。

都满足SQL需求的前提下,推荐优先使用Inner join(内连接),如果要使用left join,左边表数据结果尽量小,如果有条件的尽量放到左边处理。


反例:

select * from tab1 t1 left join tab2 t2  on t1.size = t2.size where t1.id>2;

正例:

select * from (select * from tab1 where id >2) t1 left join tab2 t2 on t1.size = t2.size;

理由:


如果inner join是等值连接,或许返回的行数比较少,所以性能相对会好一点。

同理,使用了左连接,左边表数据结果尽量小,条件尽量放到左边处理,意味着返回的行数可能比较少。


10、应尽量避免在where子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。

反例:

select age,name  from user where age <>18;

正例:

//可以考虑分开两条sql写select age,name  from user where age <18;select age,name  from user where age >18;

理由:

  • 使用!=和<>很可能会让索引失效

微信截图_20231016163312.png

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
19天前
|
关系型数据库 MySQL 索引
mysql 分析5语句的优化--索引添加删除
mysql 分析5语句的优化--索引添加删除
14 0
|
2天前
|
SQL 关系型数据库 MySQL
【MySQL】SQL优化
【MySQL】SQL优化
|
2天前
|
安全 关系型数据库 MySQL
node实战——后端koa结合jwt连接mysql实现权限登录(node后端就业储备知识)
node实战——后端koa结合jwt连接mysql实现权限登录(node后端就业储备知识)
11 3
|
3天前
|
SQL 关系型数据库 MySQL
不允许你不知道的 MySQL 优化实战(一)
不允许你不知道的 MySQL 优化实战(一)
11 2
|
4天前
|
存储 缓存 关系型数据库
掌握MySQL数据库这些优化技巧,事半功倍!
掌握MySQL数据库这些优化技巧,事半功倍!
|
4天前
|
缓存 关系型数据库 MySQL
MySQL数据库优化技巧:提升性能的关键策略
索引是提高查询效率的关键。根据查询频率和条件,创建合适的索引能够加快查询速度。但要注意,过多的索引可能会增加写操作的开销,因此需要权衡。
|
5天前
|
SQL Oracle 关系型数据库
下次老板问你MySQL如何优化时,你可以这样说,老板默默给你加工资
现在进入国企或者事业单位做技术的网友越来越多了,随着去O的力度越来越大,很多国企单位都开始从Oracle向MySQL转移,相对于Oracle而言,MySQL最大的问题就是性能,所以,这个时候,在公司如果能够处理好MySQL的性能瓶颈,那么你也就很容易从人群中脱颖而出,受到老板的青睐。
23 1
|
6天前
|
关系型数据库 MySQL 中间件
【MySQL实战笔记】07 | 行锁功过:怎么减少行锁对性能的影响?-02 死锁和死锁检测
【4月更文挑战第19天】在高并发环境下,死锁发生在多个线程间循环等待资源时,导致无限期等待。MySQL中,死锁可通过`innodb_lock_wait_timeout`参数设置超时或`innodb_deadlock_detect`开启死锁检测来解决。默认的50s超时可能不适用于在线服务,而频繁检测会消耗大量CPU。应对热点行更新引发的性能问题,可以暂时关闭死锁检测(风险是产生大量超时),控制并发度,或通过分散记录减少锁冲突,例如将数据分拆到多行以降低死锁概率。
20 1
|
9天前
|
SQL 关系型数据库 MySQL
Python与MySQL数据库交互:面试实战
【4月更文挑战第16天】本文介绍了Python与MySQL交互的面试重点,包括使用`mysql-connector-python`或`pymysql`连接数据库、执行SQL查询、异常处理、防止SQL注入、事务管理和ORM框架。易错点包括忘记关闭连接、忽视异常处理、硬编码SQL、忽略事务及过度依赖低效查询。通过理解这些问题和提供策略,可提升面试表现。
30 6
|
13天前
|
SQL 关系型数据库 数据库
【后端面经】【数据库与MySQL】SQL优化:如何发现SQL中的问题?
【4月更文挑战第12天】数据库优化涉及硬件升级、操作系统调整、服务器/引擎优化和SQL优化。SQL优化目标是减少磁盘IO和内存/CPU消耗。`EXPLAIN`命令用于检查SQL执行计划,关注`type`、`possible_keys`、`key`、`rows`和`filtered`字段。设计索引时考虑外键、频繁出现在`where`、`order by`和关联查询中的列,以及区分度高的列。大数据表改结构需谨慎,可能需要停机、低峰期变更或新建表。面试中应准备SQL优化案例,如覆盖索引、优化`order by`、`count`和索引提示。优化分页查询时避免大偏移量,可利用上一批的最大ID进行限制。
39 3