【发布时间】:2019-11-20 14:30:22
【问题描述】:
我创建了两个基本项目来比较框架。在对最近的工作项目进行开发时,我注意到使用 Spring Data JPA 时查询运行速度非常慢。
我设置了一个小实验来测试 NodeJS 与 Spring Boot,以确定它是数据库还是框架。
SELECT * FROM v$version;
Oracle Database 12c 企业版 12.1.0.2.0 - 64 位生产
该数据库位于 400 英里外的另一个设施中,会引入大约 60-80 毫秒的网络延迟。
-------------- -------- ------------
ID NOT NULL NUMBER
AR VARCHAR2(10)
MOD_TIME DATE
MOD_UID VARCHAR2(10)
ACTIVE_IND VARCHAR2(1)
WORK_ID NUMBER
在我们的测试环境中,这个数据库中有 4533 条记录。我们有大约 9000 个在生产中。本实验将使用测试环境运行。
弹簧设置:
start.spring.io 并选择 Web ,JPA, Oracle Driver, lombok
创建了一个实体类
@Entity
@Table(name = "t_test")
@Data
public class TTest implements Serializable {
private static final long serialVersionUID = 3305605889880335034L;
@Id
@Column(name = "ID")
private int id;
@Column(name = "AR")
private String ar;
@Column(name = "mod_time")
private Timestamp modTime;
@Column(name = "mod_uid")
private String modId;
@Column(name = "active_ind")
private String activeInd;
@Column(name = "work_id")
private Integer wid;
}
然后是一个简单的存储库来运行 findAll() 查询
@Repository
public interface TTestRepo extends JpaRepository<TTest, Integer> {}
最后是控制器
@RestController
@Slf4j
public class TestController {
@Autowired
TTestRepo repo;
@GetMapping("/testDb")
public List<TTest> testDb(){
return repo.findAll();
}
}
我使用 application.properties 连接到数据库
spring.datasource.url=blah
spring.datasource.username=blah
spring.datasource.password=blah
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.jpa.show-sql=true
logging.level.org.hibernate.SQL=DEBUG
NodeJS 设置
只是一个安装了 oracledb 的简单快速应用程序。
const express = require('express')
var oracledb = require('oracledb')
oracledb.getConnection(
{
//removed for obvious reasons
},
function(err, connection) {
console.log('trying to connect...')
if (err) {
console.error(err)
return
}
global.connection = connection
}
)
global.transformResults = function transformResults(result) {
let finalResults = []
let obj = {}
result.rows.forEach((row) => {
result.metaData.forEach( (meta, j) => {
obj[meta.name] = row[j]
})
finalResults.push(obj)
obj = {}
})
return finalResults
}
// Create express instnace
const app = express()
// Require API routes
const users = require('./routes/users')
// Import API Routes
app.use(users)
// Export the server middleware
module.exports = {
path: '/api',
handler: app
}
users.js 只是我运行查询的路由器或休息端点
const { Router } = require("express");
const router = Router();
router.get("/testDb", async function(req, res, next) {
connection.execute(
"SELECT * from t_test",
function(err, result) {
if (err) {
console.error(err)
return
}
res.json(transformResults(result));
}
)
});
module.exports = router;
基准测试
对于 Spring Data JPA,我做了这个基准测试
/**
* @author Jake Perkins on 11/20/2019
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class BenchMark {
@Autowired
TestController controller;
@Test
public void benchmarkDb(){
int testLength = 100;
long startTime = System.currentTimeMillis();
for(int i = 0; i < testLength; i++){
controller.testDb(); //Measure execution time for this method
}
long endTime = System.currentTimeMillis();
long durationInMillis = (endTime - startTime); //Total execution time in milliseconds
BigDecimal averageInSeconds = BigDecimal.valueOf(durationInMillis/testLength).movePointLeft(3);
System.out.println(averageInSeconds);
}
}
输出:
23.463
NodeJS 基准测试是使用以毫秒为单位的开始时间和以毫秒为单位的结束时间之间的差异进行类似计算的。
实验结果
我在两种环境中都运行了 100 次查询,并收集了以下平均时间。
Spring Boot:23.4 秒
NodeJS:2.9 秒
Oracle SQL Developer:2.6 秒
在收集 4533 条记录时(在我的具体情况下),Spring Boot 所用的时间大约是节点 JS 的 8 倍。为什么?
【问题讨论】:
-
能否提供您确定基准时间的代码
-
你试过直接使用 JDBC 吗? Spring 和 Hibernate 使用反射/代理将数据转换回来。此外,这是针对单个查询还是您尝试在同一个 JVM 中多次运行查询(以确保预热)?
-
@DanW 不,我没有尝试过直接的 JDBC,但是这个问题具体与 Spring Data JPA 有关。是的,我在同一个 JVM 中多次运行此查询。这个查询实际上是我在工作中创建的应用程序的重要组成部分。我已经运行了这个查询数百次(如果不是数千次)。这个实验的灵感来自于我每次测试我的应用程序界面都会等待很长时间。
-
尝试分享 Spring Data 的基准测试代码。根据我的经验,这种行为根本不正常。
-
nodejs 上没有缓存也没有水合。虽然有标准的 jpa 设置。但仍然不应该产生那么大的延迟。
标签: java node.js spring-boot express spring-data-jpa