基于MYSQL的JAVA初级优化措施

世界是草台班子,这句话视乎很流行! 经历过几家创业公司的项目优化,以及大公司项目. 很多优化非常初级,用心点都能自己找出来!  其实主要原因当初是为了赶进度,能省则省.什么设计啊? 什么性能压测啊. 都省掉吧! 质量都要靠测试人员帮忙找出来,更何况是性能问题呢!  那怕是配齐了测试人员,一上线各种BUG起飞,然后经过个把月打补丁才稳定下来!

各位JAVA大神是不是都是这样的体会!  更何况是全栈JAVA工程师一手操办! 为了降本增效,大量使用插件,自动化工具以及框架. 

系统一慢,立马甩锅到数据库上, 这点是酒精考验的真理! 毕竟人家数据库只有一台,而应用使用微服务架构可以N台.

数据库慢,慢在哪里? 为什么以前不慢,现在就慢了呢? 这是经常被拷问的问题

可以说从三个方面探讨数据库慢的原因

1 自然是数量多了,经过1-2年的日积月累

2 用户多了,经过销售和老板的勤奋努力

3 SQL变多了,经过产品经理和开发人员的努力

其实第3点,很多人没有注意到.原本系统的业务开始之处比较少的SQL,后期不断满足需求,自然功能越多,SQL也越多. 这一部分造成单位时间内SQL请求量增多,也就会导致各种资源的

针对 1-2 点 数据库端 可以采用的优化措施是

1 范围分区
2 冷热分表
3 读写分离
4 添加索引

范围分区: 一般情况下大家都是基于时间范围的分区,根据业务查询范围特性,选择合适的时间进行分区;
冷热分表: 这是根据业务时间来说,100%把不需要的数据迁移到历史表中,可以说成归档.

读写分离: 一般情况下数据库还有一台作为灾备的实例,一般情况下都是空闲,自然要利用起来,比如说做些统计查询的工作, 承担业务某些统计的功能.

添加索引:根据SLOW日志 无脑地,或者稍微考虑下添加索引.

数据库我们说完了,应该说JAVA优化了.我只是个DBA,能看懂JAVA代码,自然不会班门弄斧!

JAVA 有模式 M  V  C  也就是分层. 现在SPRING BOOT 微服务时代,那就是前后端分离.

M 自然是指数据端了.

V 是指 VIEW 前端页面

C 是指控制端,以前处理WEB请求地址的,现在叫后端,主要处理业务逻辑的.


V 前端页面

1 数据缓存, 前端在下不太懂,咨询本公司前端的妹子,VUE可以本地缓存,各种浏览器都有F12查看的

比如微软的新浏览器

在这里先说下我们业务, 电商平台,有商城,有客户,有商户,有银行支付渠道; 
那么我们可以把常用的选择项存入缓存中,每个页面就不用去请求接口获得对应的值. 比如说我们的的省份,支付渠道.这些不经常的改变值完全存在前端浏览器内.

2 接口无效调用

 一般页面基本分为 上面条件选择,中间查询按钮,下面分页的具体内容,然后下一页的导航条;

很多时候我们JAVA同学喜欢分页插件,其实那个分页插件很弱智,它只要你提供一个主查询SQL,它就在外面包一层用来统计总数
主查询语句, 有的插件还提供LIMIT 选择

SELECT A.*,B.*,C.*
FROM A
LEFT JOIN B ON A.ID=B.ID
LEFT JOIN C ON A.ID=C.ID
WHERE 1=1
AND A.X=?
AND B.Y=?
AND C.Z=?
ORDER BY A.AGE DESC

那么统计总数是:

​SELECT COUNT(*)
FROM
(
SELECT A.*,B.*,C.*
FROM A
LEFT JOIN B ON A.ID=B.ID
LEFT JOIN C ON A.ID=C.ID
WHERE 1=1
AND A.X=?
AND B.Y=?
AND C.Z=?
ORDER BY A.AGE DESC
) TEMP;

​

咋一看 插件挺好的,SQL也没有毛病,其实仔细一看也没有毛病,不就是多了个ORDER BY 嘛!
这个先放下说, 此时此刻其实这两个SQL语句可能在两个接口里, 也许是在一个接口里. 如果在两个接口里,使用浏览器的F12功能查看接口调用.要么喊JAVA打印SQL日志.那么我们在点击下一页的时候,你会发现它会再去统计一次.

很显然这个统计是没有必要的,有的同学会找借口说是看实时信息. 实时的信息,需要点击下一页吗?
很显然对方没有对需求做得很清晰! 工作没有做到位!

插件只能统计总数,不能统计其它的,如果你需要统计金额SUM(),平均每单费用. 那么你的另外写个SQL并开发个接口提供前端.也就是前端页面的这部分.

 

​SELECT SUM(A.MONEY),AVG(B.FEE)
FROM
(
SELECT A.*,B.*,C.*
FROM A
LEFT JOIN B ON A.ID=B.ID
LEFT JOIN C ON A.ID=C.ID
WHERE 1=1
AND A.X=?
AND B.Y=?
AND C.Z=?
ORDER BY A.AGE DESC
) TEMP;​

​

SQL 就这样写,我们都是搬运工而已!
因此这两个接口完全可以合并在一起
 

​SELECT COUNT(*),SUM(A.MONEY),AVG(B.FEE)
FROM
(
SELECT A.*,B.*,C.*
FROM A
LEFT JOIN B ON A.ID=B.ID
LEFT JOIN C ON A.ID=C.ID
WHERE 1=1
AND A.X=?
AND B.Y=?
AND C.Z=?
ORDER BY A.AGE DESC
) TEMP;​

没有数据的时候 分页SQL接口是否要调用?

在分页插件,那是一定的. 所以我们可以通过统计接口来判断是否有数据,有数据就,无数据就别去查询了,否则那就慢给你看!
因为没有符合条件的数据,MYSQL 会遍历所有,然后返回LIMIT 10给你, 这个遍历那怕是索引也会很久. 好比你明明知道LIST<CHAR>里面没有数字, 你要求LIMIT ,那么它会从头到尾查一个遍给你看.
为什么你会明明知道? 因为COUNT(*)返回是零!   其实你是不知道的,没有意思到而已. 

3  默认条件

我们草台班子,急于求成, 一般都会把这个默认条件给忘了. 让用户随意选择时间范围, 数据量一大,基本就是全表扫描,那怕你创建索引也是没有用的!

4 深翻页

 有很多技术来解决深翻页情况,实际上没有实际价值. 最好就是明确告诉对方 超过1千行,或者1万行.多余的请通过其它途径,要么导出,要么增加选择条件.

5 默认排序

一般情况下,我们是提供某个时间的倒排序返回数据, 也就是最新的订单时间. 

ORDER BY  CREATE_TIME DESC LIMIT 0, 10;

有的时候需要支持返回的字段各种排序,就是让用户点击分页上的字段正反去排序.很多时候JAVA同学就直接把字段传回给DB,然后DB去排序
类似如下伪代码:

IF>> VO.CREATE_TIME IS NULL THEN ORDER BY CREATE_TIME DESC <<END IF
IF>> VO.PAY_TIME IS NULL THEN ORDER BY PAY_TIME DESC <<END IF
IF>> VO.SENDGOODS_TIME IS NULL THEN ORDER BY SENDGOODS_TIME DESC <<END IF

如同上面的SQL 3个表,返回未知数的字段,那么可以任意个字段可能去排序.
MYSQL排序能力是不强的,它需要借助索引,否则它SORT内存超过了,会使用磁盘文件进行排序.
建索引,你不可能建那么多字段吧?
 

那么如何解决呢? 

方法一 前端页内排序,就是说用户点击其它字段排序的时候,就当前页做排序,下一页不做

这个方法 用户会感觉有点不太好! 因为用户点击的是第一页排序,到了第2页就变回默认的排序字段.

方法 二 页面上只提供默认的几个排序字段 页内不支持其它字段排序. 前提是产品经理做好需求调研.

方法 三 数据全拉到前后端排序
因为我们规定了只返回1K,或者1W数据, 那么我们可以在后端进行排序,比如说LIST<MAP> 只要前端页面的PAGE_ID,那么就保留该数据在JVM内. 不过这样设计导致后端有状态化,导致JVM内存占用太多的情况.

那么把数据全拉到前端缓存起来,也是可以的! 

C 后端的DAO方法复用

JAVA 如何优化,在下不敢瞎逼逼. 不过遇到DAO方法复用问题. 很多情况下JAVA同学为了赶进度,会无限拔高复用的地位! 导致无法理解复用,为了复用而去复用.视乎违背了面向对象设计思想!

汇编语言有子过程,C语言有函数,C++语言有类, 数据库有存储过程. 这些都是为了重用,复用而实现的. 因为程序都是数据结构+算法. 那么程序的基本结构都是一致的,唯独数据不一样而已 好比说

1+1=2; 
2+2=4;
4+4=8;
8+8=16

那么抽象成 X+Y=Z
那么我们可以写成C函数如下: 

int add(int x, int y)
{
  return x+y;
}

这样我们就可以重用该函数,当遇到其它数字加法的时候.就可以重用该函数.
类和对象也是这样,抽取共同拥有的方法和属性,

然而 DAO方法复用却走了极端. 如果只是简单地把表当作一个类,每行数据当成一个类的实例化对象,好像没有什么问题! 
问题在于把多表关联后的结果当作个VIEW OBJECT对象. 那问题有点大! 
比如说 用户查看订单, 商家查看订单,商城查看订单, 都是以订单对象为主, 除了订单对象外还要LEFT JOIN 其它的表. 假设拿商城看订单情况,假设是5张表的话,

SELECT A1.*,A2.*,A3.*,A4.*,A5.*
FROM A1
LEFT JOIN A2 ....
LEFT JOIN A3 ...
LEFT JOIN A5 ....
WHERE 1=1
AND A1.X=?
....
AND A5.Z=?
ORDER BY A1.CREATE_TIEM DESC 
LIMIT 0,10;

通过MYBAITS新功能自由地把结果集映射到VIEW OBJECT对象上. 那么这就是某个DAO方法之一

然后用户也用该方法,商家也用该DAO的方法,返回的属性,大部分不用,只用其中某些属性,然后打包成JSON格式返回给前端. 也许直接丢给前端,然后前端自己裁剪.

这有什么问题吗?

1  用户和商家查询次数,自然是比商城多得多,那么造成无用的数据来回传来删减.

数据从DB拉到应用端什么时候才释放?
(1)ResultSet关闭:一旦ResultSet关闭,JDBC驱动会释放与该ResultSet相关的资源,包括内存。
(2)web请求结束,栈空间自动释放,产生的对象在堆内存中,大概率是在新生代,直到被jvm yonggc回收。
 

 数据库查询返回100个字段,DAO映射了50个字段,另外50个字段会怎么样?
(1)网络传输:所有返回的100个字段数据都会通过网络传输到应用服务器,这里有mysql的内存占用,cpu计算,以及网络消耗

(2)在JDBC层面,ResultSet会包含所有100个字段的数据,这些数据会暂时保存在内存中,直到被消费或ResultSet被关闭。这里占用的jvm堆内存中的新生代中,直到被jvm yonggc回收。

(3)DAO只会映射其中的50个字段,剩下的50个字段不会被映射到对象中。但由于数据已经被传输到应用服务器,因此这些未映射的字段依然会占用的jvm堆内存中的新生代中,直到被jvm yonggc回收。

DAO方法返回50个字段,一个服务只要10个字段,那么另外40个字段会怎么样?
包含50个字段的对象会被创建并保留,在jvm 堆内存中的新生代中。这些对象在内存中占用的空间包括所有50个字段的空间。

 从上面情况来说 造成 DB端内存浪费,网络包大,JVM 结果集内存占用,如果开启了1-2级别缓存下;
然后 LIST数组内存变大.

2 LEFT JOIN 不必要化
MYSQL 阿里规范要求不超过5个表关联,为什么呢? 主要是因为MYSQL多表个关联能力很弱,所以速度会直线下降. 虽然后期MYSQL8得到了改进. 好像说到这没有问题,多个表就多个表,没啥关系!

问题在于有些查询不需要多个表,比如用户来说他只需要2个表关联,那么多余的3个表会怎么样呢?

那怕WHERE没有提供A3,A4,A5的条件呢?  MYSQL依旧去做关联运算,

3 反对SELECT 星

以前SPRING MVC MYBAITS 时候 如果SELECT * 后, DB添加字段会让JAR自动报错.

那个时候是禁止SELECT *的. 可是现在SPRING BOOT 微服务时代,不知道咋的,SELECT * 后DB添加字段,也不报错,可以正确匹配到旧字段. 这样JAVA同学开心得很.

总的来说这就是挖了性能的坑, 影响DB,影响网络,影响JVM内存. 

主要的是DB一般就一台,顶多主从读写分离两台来工作, 或许搞个微服务,多台DB来承担.只不过性能的坑继续延后爆发而已.

为什么我比较讨厌复用呢? 因为不好优化SQL啊, 如果要改写SQL,你说怎么改? 一个DAO的方法被复用了,你不知道哪些服务使用了该方法, 要在上面加个FORCE INDEX 索引提示, 有些服务因为加了提升从而导致更加的慢!

其实这DAO复用走了极端, 违背了JAVA的高内聚,低耦合的要求! 成了诗山代码. 本来DAO方法就是个SQL模版, 要加上条件再加上具体值才能形成具体的SQL.MYSQL只能对具体的SQL进行优化分析. ORACLE就不一样,它可以对加了条件的SQL模版优化. 并且自动分析没有必要的LEFT JOIN.

所以在此建议JAVA同学放弃这种DAO复用. 不过就是复制粘贴然后删除没有必要的字段和LEFT JOIN表就是. 再新建个VIEW OBJECT对象来映射结果集. 这样确实工作量有些大, 但是这样业务流程明确,方便日后更改

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

临时关闭Windows安全中心

在使用WindowsOS是&#xff0c;微软安全中心是我们必不可少的安全防护&#xff0c;但有时我们也会产生想要将其关闭的需求&#xff0c;下面将要介绍如何临时关闭Windows的安全中心 一、打开安全中心、选择“病毒与威胁防护”&#xff0c;点击“管理设置” 之后将其实时保护关闭…

Vue3中的常见组件通信(超详细版)

Vue3中的常见组件通信 概述 ​ 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refs、parent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。 组件关系传递方式父传子1. props2. v-model3. $refs4. 默认…

M12单端I/O预铸法兰插座A-code

M12单端I/O预铸法兰插座A-code概述 M12单端I/O预铸连接器A-code是一种常用于工业自动化领域的连接器件&#xff0c;主要用于传感器和执行器之间的信号传输。它的设计遵循国际标准IEC 61076-2-101&#xff0c;具有良好的防水防尘性能&#xff0c;通常达到IP67的保护等级。M12连…

自学鸿蒙HarmonyOS的ArkTS语言<一>基本语法

一、一个ArkTs的目录结构 二、一个页面的结构 A、装饰器 Entry 装饰器 : 标记组件为入口组件&#xff0c;一个页面由多个自定义组件组成&#xff0c;但是只能有一个组件被标记 Component : 自定义组件, 仅能装饰struct关键字声明的数据结构 State&#xff1a;组件中的状态变量…

【Linux硬盘读取】Windows下读取Linux系统的文件解决方案:Linux Reader4.5 By DiskInternals

前言 相信做机器视觉相关的很多人都会安装 Windows 和 Linux 双系统。在 Linux 下&#xff0c;我们可以很方便的访问Windows的磁盘&#xff0c;反过来却不行。但是这又是必须的。通过亲身体验&#xff0c;向大家推荐这么一个工具&#xff0c;可以让 Windows 方便的访问 Ext 2/3…

机器学习课程复习——逻辑回归

1. 激活函数 Q:激活函数有哪些? SigmoidS型函数Tanh 双曲正切函数

SpringBoot+Maven项目的配置构建

文章目录 1、application.properties2、pom.xml 1、application.properties 也可使用yml yaml #静态资源 spring.mvc.static-path-pattern/images/** #上传文件大小设置 spring.http.multipart.max-file-size10MB spring.http.multipart.max-request-size10MBspring.mvc.path…

50万定律:任何单位和任何职业,只要工资年收入大于50万,基本上都要牺牲个人生活,无论是医生还是教师...

“我今年30岁&#xff0c;在北京&#xff0c;年薪50万&#xff0c;但我一点也不快乐……” 朋友圈看到朋友的感慨&#xff0c;配图是深夜加班的CBD夜景&#xff0c;评论区不出所料&#xff0c;一半是羡慕&#xff0c;一半是“凡尔赛”。 年薪50万&#xff0c;在很多人眼里&am…

Spring的启动扩展点机制详解

在Java的世界中&#xff0c;我们知道Spring是当下最主流的开发框架&#xff0c;没有之一。而在使用Dubbo、Mybatis等开源框架时&#xff0c;我们发现可以采用和Spring完全一样的使用方式来使用它们。 可能你在平时的使用过程中并没有意识到这一点&#xff0c;但仔细想一想&…

NUC 14 Pro+:解锁AI前沿,体验科技之美

NUC 14 Pro不仅是一台迷你主机&#xff0c;更是生活品质的体现。如果你也是细节控&#xff0c;那这篇文章或许是你需要的。 超小体积 造型精致 NUC 14 Pro作为迷你PC拥有约0.66L的超小体积&#xff0c;如果你对升没有概念&#xff0c;那你可以想象&#xff1a;它的机箱面积144…

御道源码(ruoyi-vue-pro)个人使用小结

御道源码&#xff08;ruoyi-vue-pro&#xff09;个人使用小结 一、Git地址 1、平台项目简介及地址 2、开发指南&#xff0c;如图所示&#xff0c;部分功能需要收费&#xff0c;可自行了解 二、项目文件夹结构示例&#xff1a; 三、技术介绍 1.基于 Spring Boot MyBatis P…

解锁空间数据奥秘:ArcGIS Pro与Python双剑合璧,处理表格数据、矢量数据、栅格数据、点云数据、GPS数据、多维数据以及遥感云平台数据等

ArcGISPro提供了用户友好的图形界面&#xff0c;适合初学者快速上手进行数据处理和分析。它拥有丰富的工具和功能&#xff0c;支持各种数据格式的处理和分析&#xff0c;适用于各种规模的数据处理任务。ArcGISPro在地理信息系统&#xff08;GIS&#xff09;领域拥有广泛的应用&…

编程书籍的枯燥真相:你也有同样的感受吗?

讲动人的故事,写懂人的代码 我得实话实说,你可能已经发现市面上的大部分编程入门书籍有些枯燥。这个问题的根源在于许多作者把本应该充满乐趣和吸引力的入门指南,写得就像一本沉闷的参考手册。这就好比把一本充满冒险和乐趣的旅行日记,写成了一本单调乏味的字典。 我完全理…

基于uni-app和图鸟UI的云课堂小程序开发实践

摘要&#xff1a; 随着移动互联网的快速发展&#xff0c;移动学习已成为教育领域的重要趋势。本文介绍了基于uni-app和图鸟UI框架开发的云课堂小程序&#xff0c;该小程序实现了移动教学、移动学习、移动阅读和移动社交的完美结合&#xff0c;为用户提供了一个便捷、高效的学习…

Flutter【组件】可折叠文本组件

简介 flutter 可折叠文本组件。 点击展开&#xff0c;收起折叠文本。支持样式自定义 github地址&#xff1a; github.com/ThinkerJack… pub地址&#xff1a;https://pub.dev/packages/jac_uikit 展开收起文本 使用方式&#xff1a; ExpandableText(content: 测试 * 50,ma…

C语言| 宏定义

#define 标识符 常量 这是固定格式&#xff0c;一般放在#include <stdio.h>后面&#xff0c;标识符是临时的符号&#xff0c;预处理之后就不存在了。 宏所表示的常量可以是数字、字符、字符串、表达式。其中最常用的是数字。 宏定义最大的好处是方便修改常量&#xff…

MUR20100DC-ASEMI智能AI应用MUR20100DC

编辑&#xff1a;ll MUR20100DC-ASEMI智能AI应用MUR20100DC 型号&#xff1a;MUR20100DC 品牌&#xff1a;ASEMI 封装&#xff1a;TO-263 恢复时间&#xff1a;35ns 最大平均正向电流&#xff08;IF&#xff09;&#xff1a;20A 最大循环峰值反向电压&#xff08;VRRM&a…

等保2.0中,如何确保云服务提供商的数据主权合规?

等保2.0&#xff08;网络安全等级保护2.0&#xff09;为了确保云服务提供商的数据主权合规&#xff0c;提出了若干关键措施和要求&#xff0c;主要包括但不限于以下几点&#xff1a; 1. 数据地理位置要求&#xff1a;明确规定云服务提供商必须保证所有基础设施位于中国境内&am…

VB计算圆柱体积和表面积

已知圆半径和圆柱的高&#xff0c;计算圆柱体积和表面积。 Public Class Form1Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.ClickConst PI 3.14159Dim r As Integer, h As IntegerDim t As Single, s As Singler Val(TextBox1.Text)h V…

SpringMVC系列七: 手动实现SpringMVC底层机制-上

手动实现SpringMVC底层机制 博客的技术栈分析 &#x1f6e0;️具体实现细节总结 &#x1f41f;准备工作&#x1f34d;搭建SpringMVC底层机制开发环境 实现任务阶段一&#x1f34d;开发ZzwDispatcherServlet&#x1f966;说明: 编写ZzwDispatcherServlet充当原生的DispatcherSer…