Java性能优化-书写高质量SQL的建议(如何做Mysql优化)

场景

Mysql中varchar类型数字排序不对踩坑记录:

Mysql中varchar类型数字排序不对踩坑记录_mysql vachar排序有问题-CSDN博客

为避免开发过程中针对mysql语句的写法再次踩坑,总结开发过程中常用书写高质量sql的一些建议。

注:

博客:
霸道流氓气质-CSDN博客

实现

查询SQL尽量不要使⽤select *而是select具体字段

理由:

只取需要的字段,节省资源、减少⽹络开销。

select * 进⾏查询时,很可能就不会使⽤到覆盖索引了,就会造成回表查询。

如果知道查询结果只有⼀条或者只要最大最小⼀条记录建议用limit 1

反例:

select id,name from student where name ='霸道'

正例:

select id,name from student where name ='霸道' limit 1

理由:

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

当然,如果name是唯⼀索引的话,是不必要加上limit 1了,

因为limit的存在主要就是为了防⽌全表扫描,从⽽提⾼性能,

如果⼀个语句本身可以预知不⽤全表扫描,有没有limit ,性能的差别并不⼤。

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

反例:

select id,name from student where userid=1 or age = 18

正例:

使用union all

select id,name from student where userid=1 union all  select id,name from student where age = 18

理由:

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

假设它走了userId的索引,但是走到age查询条件时,它还得全表扫描,也就是需要三步:全表扫描+索引扫描+合并,如果它一开始

就走全表扫描,直接一遍扫描就完事。

优化limit分页

反例:

select id,name from student limit 10000,10

正例:

方案1:返回上次查询的最大记录(偏移量)

select id,name from student where id > 10000 limit 10

方案2:order by + 索引

select id,name from student order by id limit 10000,10

方案3:在业务允许的情况下限制页数

select id,name from student order by id limit 10,10

理由:

当偏移量最⼤的时候,查询效率就会越低,因为Mysql并⾮是跳过偏移量直接去取后⾯的数据,

⽽是先把偏移量+要取的条数,然后再把前⾯偏移量这⼀段的数据抛弃掉再返回的。

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

⽅案⼆使⽤order by+索引,也是可以提⾼查询效率的。

优化like语句

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

反例:

select id,name from student where name like '%badao'

正例:

select id,name from student where name like 'badao%'

理由:

Mysql中LIKE查询以%开头不一定会让索引失效。如果查询的结果中只包含主键和索引字段则会使用索引,反之则不会。

下面进行验证,在sname字段行添加普通索引

CREATE INDEX name_index on test_student(sname)

测试以%开头且只包含主键和索引字段,测试结果为使用索引

explain SELECT sid,sname,sage from test_student WHERE sname like '%三';

测试以%开头单包含主键和索引字段以及其它字段,测试结果为全表扫描

explain SELECT sid,sname,sage from test_student WHERE sname like '%三';

测试以%结尾且包含主键和索引字段以及其它字段,测试结果为使用索引

explain SELECT sid,sname,sage from test_student WHERE sname like '张%';

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

比如查询某个用户是否是会员

反例:

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;

理由:

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

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

业务需求:

查询最近七天内登陆过的⽤户(假设loginTime加了索引)

反例:

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

正例:

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

理由:

索引列上使用Mysql的内置函数,会导致索引失效

失效测试

explain SELECT sid,sname,sage from test_student WHERE DATE_ADD(sdate,INTERVAL 7 DAY)>=NOW();

不失效测试

explain SELECT sid,sname,sage from test_student WHERE sdate >=DATE_ADD(NOW(),INTERVAL -7 DAY);

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

在sage上添加索引

CREATE INDEX age_index on test_student(sage)

反例:

explain SELECT sid,sname,sage from test_student WHERE sage-1 = 10

正例:

explain SELECT sid,sname,sage from test_student WHERE sage = 11

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是等值连接,或许返回的⾏数⽐较少,所以性能相对会好⼀点。

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

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

反例:

explain SELECT sid,sname,sage from test_student WHERE sage <> 11

使用联合索引时,注意索引列的顺序,⼀般遵循最左匹配原则

组合索引是在多个字段上创建一个索引。

CREATE INDEX group_index on fruit(id,name,price);

可以看到如果查询时包含了id则使用了索引,否则不使用索引

EXPLAIN SELECT * FROM fruit WHERE id='1' AND city = '北京';
EXPLAIN SELECT * FROM fruit WHERE name='苹果' AND city = '北京';

理由:

当我们创建⼀个联合索引的时候,如(k1,k2,k3),相当于创建了(k1)、(k1,k2)和(k1,k2,k3)三个索引,

这就是最左匹配原则。

联合索引不满⾜最左原则,索引⼀般会失效,但是这个还跟Mysql优化器有关的。

对查询进行优化,应考虑在where及order by涉及的列上建立索引,尽量避免全表扫描

见文知意,不再举例。

如果插入数据过多,考虑批量插入

参考如下

SpringBoot+MybatisPlus+Mysql实现批量插入万级数据多种方式与耗时对比:

SpringBoot+MybatisPlus+Mysql实现批量插入万级数据多种方式与耗时对比_mybaytis-plus大数据批量插入-CSDN博客

在适当的时候,使用覆盖索引

覆盖索引能够使得你的SQL语句不需要回表,仅仅访问索引就能够得到所有需要的数据,⼤⼤提⾼了查询效率。

覆盖索引(Covering Index)是指一个查询操作中,数据库可以通过遍历索引而不需要访问数据行就可以返回查询所需要的数据的情况。

这样可以减少磁盘I/O,提高查询效率。

在MySQL中,要创建覆盖索引,需要确保查询中的所有列都是索引的一部分,并且索引的顺序尽可能地匹配查询中列的顺序。

例如,假设有一个表users,它有以下列和索引:

CREATE TABLE test_users (id INT NOT NULL AUTO_INCREMENT,first_name VARCHAR(50),last_name VARCHAR(50),email VARCHAR(100),PRIMARY KEY (id)
);CREATE INDEX idx_name ON test_users (first_name, last_name);

如果你想要查询用户的first_name和last_name,并且你知道这些信息将用于很多查询,你可以创建一个覆盖索引

CREATE INDEX idx_covering ON test_users (first_name, last_name);

这样,当你执行一个只需要这些列的查询时

SELECT first_name, last_name FROM test_users WHERE first_name = 'John';

MySQL可以通过扫描索引idx_covering而不是查询数据行来提供结果,从而提高查询效率。

慎用distinct关键字

distinct 关键字⼀般⽤来过滤重复记录,以返回不重复的记录。

在查询⼀个字段或者很少字段的情况下使用时,给查询带来优化效果。

但是在字段很多的时候使⽤,却会大大降低查询效率。

反例:

SELECT DISTINCT * from user;

正例:

select DISTINCT name from user;

理由:

带distinct的语句cpu时间和占⽤时间都⾼于不带distinct的语句。

因为当查询很多字段时,如果使⽤distinct,数据库引擎就会对数据进⾏⽐较,过滤掉重复数据,

然⽽这个⽐较、过滤的过程会占⽤系统资源,cpu时间。

删除冗余和重复索引

反例:

KEY 'idx_userId' ('userId') KEY 'idx_userId_age' ('userId','age')

正例:

删除userId索引,因为组合索引(A,B)相当于创建了(A)和(A,B)索引。

理由:

重复的索引需要维护,并且优化器在优化查询的时候也需要逐个地进行考虑,这会影响性能的。

如果数据量较大,优化你的修改/删除语句

避免同时修改或删除过多数据,因为会造成cpu利⽤率过⾼,从而影响别人对数据库的访问。

⼀次性删除太多数据,可能会有lock wait timeout exceed的错误,所以建议分批操作。

where子句中考虑使用默认值代替null

反例:

select * from user where age is not null;

正例:

select * from user where age>0;

设置age列0为默认值。

理由:

并不是说使⽤了is null 或者 is not null 就会不⾛索引了,这个跟mysql版本以及查询成本都有关。

如果mysql优化器发现,⾛索引比不⾛索引成本还要⾼,肯定会放弃索引,这些条件 !=,isnull,isnotnull 经常被认为让索引失效,

其实是因为⼀般情况下,查询的成本⾼,优化器⾃动放弃索引的。

如果把null值,换成默认值,很多时候让⾛索引成为可能,同时,表达意思会相对清晰⼀点。

不要有超过5个以上的表连接

连表越多,编译的时间和开销也就越⼤。

把连接表拆开成较小的几个执行,可读性更⾼。

如果⼀定需要连接很多表才能得到数据,那么意味着糟糕的设计了

exist&in的合理利用

假设表A表示某企业的员⼯表,表B表示部门表,查询所有部⻔的所有员⼯,很容易有以下SQL

 select * from A where deptId in (select deptId from B);

这样写等价于:

先查询部门表B

select deptId from B

再由部门deptId,查询A的员⼯

select * from A where A.deptId = B.deptId

除了使用in,我们也可以使用exist实现一样的查询功能

select * from A where exists (select 1 from B where A.deptId = B.deptId);

因为exists查询的理解就是,先执⾏主查询,获得数据后,再放到子查询中做条件验证,根据验证结果(true或者false),

来决定主查询的数据结果是否保留。

那么,这样写就等价于

select * from A,先从A表做循环

select * from B where A.deptId = B.deptId,再从B表做循环.

数据库最费劲的就是跟程序链接释放。

假设链接了两次,每次做上百万次的数据集查询,查完就⾛,这样就只做了两次;

相反建⽴了上百万次链接,申请链接释放反复重复,这样系统就受不了了。

即mysql优化原则,就是小表驱动大表,小的数据集驱动大的数据集,从而让性能更优。

因此,我们要选择最外层循环小的,也就是,如果B的数据量小于A,适合使⽤in,

如果B的数据量大于A,即适合选择exist。

尽量使用union all 替换union

如果检索结果中不会有重复的记录,推荐union all 替换 union

反例:

select * from user where userid=1 union select * from user where age = 10

正例:

select * from user where userid=1 union all select * from user where age = 10

理由:

如果使用union,不管检索结果有没有重复,都会尝试进⾏合并,然后在输出最终结果前进行排序。

如果已知检索结果没有重复记录,使⽤union all 代替union,这样会提⾼效率。

索引不宜太多,一般5个以内

索引并不是越多越好,索引虽然提⾼了查询的效率,但是也降低了插⼊和更新的效率。

insert或update时有可能会重建索引,所以建索引需要慎重考虑,视具体情况来定。

⼀个表的索引数最好不要超过5个,若太多需要考虑⼀些索引是否没有存在的必要。

尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型

理由:

相对于数字型字段,字符型会降低查询和连接的性能,并会增加存储开销。

另外,参考文首博客踩坑。

索引不适合建在有大量重复数据的字段上,如性别这类型数据库字段

因为SQL优化器是根据表中数据量来进⾏查询优化的,如果索引列有⼤量重复数据,

Mysql查询优化器推算发现不走索引的成本更低,很可能就放弃索引了。

尽量避免向客户端返回过多数据量

分页实现。

当在SQL语句中连接多个表时,请使⽤表的别名,并把别名前缀于每⼀列上,这样语义更加清晰

规范使用表别名。

尽可能使用varchar/nvarchar代替char/nchar

理由:

因为⾸先变长字段存储空间小,可以节省存储空间。

其次对于查询来说,在⼀个相对较小的字段内搜索,效率更高。

为了提⾼group by语句的效率,可以在执⾏到该语句前,把不需要的记录过滤掉

反例:

select job,avg(salary) from employee group by job having job ='president' or job = 'managent'

正例:

select job,avg(salary) from employee where job ='president' or job= 'managent' group by job;

如果字段类型是字符串,where时⼀定用引号括起来,否则索引失效

反例:

explain select * from test_student where eid = 1;

正例:

explain select * from test_student where eid = '1';

理由:

因为不加单引号时,是字符串跟数字的⽐较,它们类型不匹配,MySQL会做隐式的类型转换,

把它们转换为浮点数再做比较。

使用explain分析你SQL的计划

Mysql中索引的分类、增删改查与存储引擎对应关系:

Mysql中索引的分类、增删改查与存储引擎对应关系-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/380087.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

特征工程方法总结

方法有以下这些 首先看数据有没有重复值、缺失值情况 离散&#xff1a;独热 连续变量&#xff1a;离散化&#xff08;也成为分箱&#xff09; 作用&#xff1a;1.消除异常值影响 2.引入非线性因素&#xff0c;提升模型表现能力 3.缺点是会损失一些信息 怎么分&#xff1a;…

【C++】—— 从 C 到 C++ (下)

【C】—— 从 C 到 C &#xff08;下&#xff09; 六、引用6.1、什么是引用6.2、引用在传参的使用6.2.1、例一6.2.2、例二 6.3、引用在做返回值的使用6.4、引用的特性6.5、引用的使用总结6.6、 c o n s t const const 引用6.6.1、 c o n s t const const 引用的规则6.6.2、 c o…

福派斯三文鱼猫粮,养猫新手的福音,让猫咪爱上吃饭!

猫粮的选择对于猫咪的健康和日常饮食至关重要。福派斯三文鱼猫粮作为一款备受关注的产品&#xff0c;它在市场上表现如何呢&#xff1f;下面我们将从几个关键方面深入探讨如何选择猫粮&#xff0c;并详细分析福派斯三文鱼猫粮的优缺点。 一、了解猫咪的独特需求 首先&#xff0…

[Redis]典型应用——分布式锁

什么是分布式锁&#xff1f; 在一个分布式系统中&#xff0c;也会涉及到多个节点访问同一个公共资源的情况。此时就需要通过锁来做互斥控制&#xff0c;避免出现类似于"线程安全"的问题 举个例子&#xff0c;在平时抢票时&#xff0c;多个用户可能会同时买票&#…

ubuntu源码安装Odoo

序言:时间是我们最宝贵的财富,珍惜手上的每个时分 Odoo具有非常多的安装方式&#xff0c;除了我最爱用的 apt-get install&#xff0c;我们还可以使用git拉取Odoo源码进行安装。 本次示例于ubuntu20.04 Desktop上进行操作&#xff0c;理论上在ubuntu14.04之后都可以用此操作。 …

第1关 -- Linux 基础知识

闯关任务 完成SSH连接与端口映射并运行hello_world.py ​​​​ ssh -p 37367 rootssh.intern-ai.org.cn -CNg -L 7860:127.0.0.1:7860 -o StrictHostKeyCheckingno可选任务 1 将Linux基础命令在开发机上完成一遍 可选任务 2 使用 VSCODE 远程连接开发机并创建一个conda环境 …

关于c#的简单应用三题

#region 找出100以内与7有关的数并打印&#xff1a; public static void Print() { int sum 0; Console.WriteLine("100以内与7有关的数有&#xff1a;"); for (int i 1; i < 100; i) { if (i % 7 0) { sum; …

【AI教程-吴恩达讲解Prompts】第1篇 - 课程简介

文章目录 简介Prompt学习相关资源 两类大模型原则与技巧 简介 欢迎来到面向开发者的提示工程部分&#xff0c;本部分内容基于吴恩达老师的《Prompt Engineering for Developer》课程进行编写。《Prompt Engineering for Developer》课程是由吴恩达老师与 OpenAI 技术团队成员 I…

Flink HA

目录 Flink HA集群规划 环境变量配置 masters配置 flink-conf.yaml配置 测试 Flink HA集群规划 FLink HA集群规划如下&#xff1a; IP地址主机名称Flink角色ZooKeeper角色192.168.128.111bigdata111masterQuorumPeerMain192.168.128.112bigdata112worker、masterQuorumPee…

js 实现扫雷游戏,源码开放,支持npm引入使用

本人开发的js版本扫雷游戏 体验地址 | Github Minesweeper game Sponsors Install and use npm i minesweeper-gameimport {Map} from minesweeper-game;const map new Map();Reset Map map.reset();TS Statement interface IMapOptions {width?: number; // Map sizeh…

JMeter:BeanShell向JSR223迁移过程遭遇的java标准库不可用问题-如何切换JDK版本

前言 看过我前面文章的人想必记得我因使用BeanShell&#xff0c;遭遇过JMeter OOM的问题。所以想起官网频频提示的&#xff0c;性能测试中建议使用JSR223groovy来代替BeanShell。于是&#xff0c;开启BeanShell脚本向JSR223迁移之旅。 什么是JSR223 JSR223全称为Java Specif…

Python爬虫(1) --基础知识

爬虫 爬虫是什么&#xff1f; spider 是一种模仿浏览器上网过程的一种程序&#xff0c;可以获取一些网页的数据 基础知识 URL 统一资源定位符 uniform resource locator http: 超文本传输协议 HyperText Transfer Protocol 默认端口 80 https: 安全的超文本传输协议 security…

jenkins+gitlab+harbor+maven自动化容器部署

一、gitlab安装配置 1.1、安装 由于比较懒啊&#xff01;这里就直接使用docker安装了啊&#xff01; 没事先更新一个yum源&#xff1a;yum update -y 整一个gitlab镜像&#xff1a;docker pull gitlab/gitlab-ce 运行一个gitlab容器&#xff1a;docker run -d -p 8443:443 -p…

十七、【机器学习】【非监督学习】- K-均值 (K-Means)

系列文章目录 第一章 【机器学习】初识机器学习 第二章 【机器学习】【监督学习】- 逻辑回归算法 (Logistic Regression) 第三章 【机器学习】【监督学习】- 支持向量机 (SVM) 第四章【机器学习】【监督学习】- K-近邻算法 (K-NN) 第五章【机器学习】【监督学习】- 决策树…

[论文笔记] pai-megatron-patch Qwen2-CT 长文本rope改yarn

更改: # Copyright (c) 2024 Alibaba PAI and Nvidia Megatron-LM Team. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License a…

MongoDB常用命令大全,概述、备份恢复

文章目录 一、MongoDB简介二、服务启动停止、连接三、数据库相关四、集合操作五、文档操作六、数据备份与恢复/导入导出数据6.1 mongodump备份数据库6.2 mongorestore还原数据库6.3 mongoexport导出表 或 表中部分字段6.4 mongoimport导入表 或 表中部分字段 七、其他常用命令八…

怎么关闭 Windows 安全中心,手动关闭 Windows Defender 教程

Windows 安全中心&#xff08;也称为 Windows Defender Security Center&#xff09;是微软 Windows 操作系统内置的安全管理工具&#xff0c;用于监控和控制病毒防护、防火墙、应用和浏览器保护等安全功能。然而&#xff0c;在某些情况下&#xff0c;用户可能需要关闭 Windows…

深层神经网络示例

维度说明&#xff1a; A[L]、Z[L]&#xff1a;&#xff08;本层神经元个数、样本数&#xff09; W[L]&#xff1a;&#xff08;本层神经元个数、上层神经元个数&#xff09; b[L]&#xff1a;&#xff08;本层神经元个数、1&#xff09; dZ[L]&#xff1a;dA[L] * g’A&#xf…

【BUG】已解决:ModuleNotFoundError: No module named ‘PIL‘

已解决&#xff1a;ModuleNotFoundError: No module named ‘PIL‘ 目录 已解决&#xff1a;ModuleNotFoundError: No module named ‘PIL‘ 【常见模块错误】 错误原因&#xff1a; 解决办法&#xff1a; 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我…

时序数据库如何选型?详细指标总结!

工业物联网场景&#xff0c;如何判断什么才是好的时序数据库&#xff1f; 工业物联网将机器设备、控制系统与信息系统、业务过程连接起来&#xff0c;利用海量数据进行分析决策&#xff0c;是智能制造的基础设施&#xff0c;并影响整个工业价值链。工业物联网机器设备感知形成了…