在Postgres数据库中选择对Spring数据和JDBI进行基准测试

时间:2020-05-02 05:38:02

标签: spring spring-data-jpa jdbi

我想比较Spring数据和JDBI的性能 我使用了以下版本

Spring Boot 2.2.4.RELEASE

vs

JDBI 3.13.0

测试非常简单,从管理表中选择*并转换为管理对象列表

这是相关详细信息

带有弹簧靴

public interface AdminService extends JpaRepository<Admin, Integer> {


}

和JDBI

public List<Admin> getAdmins() {
    String sql = "Select admin_id as adminId, username from admins";
    Handle handle = null;
    try {
        handle = Sql2oConnection.getInstance().getJdbi().open();
        return handle.createQuery(sql).mapToBean(Admin.class).list();
    }catch(Exception ex) {
        log.error("Could not select admins from admins: {}", ex.getMessage(), ex );
        return null;
    } finally {
        handle.close();
    }
}

使用junit 5执行测试类

@Test
@DisplayName("How long does it take to run 1000 queries")
public void loadAdminTable() {
    System.out.println("Running load test");
    Instant start = Instant.now();
    for(int  i= 0;i<1000;i++) {
        adminService.getAdmins(); // for spring its findAll()
    for(Admin admin: admins) {
                if(admin.getAdminId() == 654) {
                    System.out.println("just to simulate work with the data");
                }
            }
    }
    Instant end = Instant.now();
    Duration duration = Duration.between(start, end);
    System.out.println("Total duration: " + duration.getSeconds());

}

我很震惊获得以下结果

春季数据:2秒 JDBI:59秒

知道我为什么得到这些结果吗?我期望JDBI更快

2 个答案:

答案 0 :(得分:2)

问题在于,Spring有很好的理由为我们管理连接生命周期 在阅读了JDBI的文档之后

每次分配连接都会降低性能 然后发布。在上面的示例中,两个insertFullContact 操作从数据库中获取单独的连接对象 连接池。

我将JDBI测试的测试代码更改为以下

@Test
@DisplayName("How long does it take to run 1000 queries")
public void loadAdminTable() {
    System.out.println("Running load test");
    String sql = "Select admin_id as adminId, username from admins";
    Handle handle = null;
    handle = Sql2oConnection.getInstance().getJdbi().open();
    Instant start = Instant.now();
    for(int  i= 0;i<1000;i++) {
        
        List<Admin> admins = handle.createQuery(sql).mapToBean(Admin.class).list();
        if(!admins.isEmpty()) {
            for(Admin admin: admins) {
                System.out.println(admin.getUsername());
            }
        }
    }
    handle.close();
    Instant end = Instant.now();
    Duration duration = Duration.between(start, end);
    System.out.println("Total duration: " + duration.getSeconds());
    
}

这样,一次打开连接,查询运行1000次

最终结果是1秒

两倍于弹簧

答案 1 :(得分:1)

一方面,您似乎犯了一些基准测试的基本错误:

  • 您没有在预热JVM。
  • 您没有以任何方式使用结果。

因此,您所看到的可能只是虚拟机不同优化的影响。 查看JMH,以提高基准。

使用外部资源进行基准测试特别困难,因为您需要控制的参数太多。 例如,一个大问题是,与数据库的连接是否实际上很慢,因为在大多数生产系统中,数据库至少实际上将位于不同的计算机上,很可能位于不同的硬件上。 在您的测试中也是这样吗?

假设您的结果是真实的,那么下一步就是调查多余的时间花在哪里。 我希望在执行SQL语句和通过网络获得结果上花费最多的时间。 因此,您应该检查实际上执行了哪些SQL语句。

这可能会为您提供一个可能的答案,即JPA正在执行很多延迟加载,甚至没有加载您真正需要的大多数。

相关问题