我试图说服“高层”使用querydsl sql来保持持久性。但是他们更喜欢spring jdbctemplate,原因是它提供了最好的原始性能。
表现是我们对课程的首要要求。这就是为什么JPA根本不是一个选择。 QueryDSL SQL开销是否过多而无法从我们的选项中删除它?
我想知道是否有任何“最近”的性能测试,以显示querydsl sql如何使用jdbctemplate和jpa。
我遇到了this。 我想知道querydsl sql在与jdbctemplate和jpa实现进行比较时的相对性能。
答案 0 :(得分:14)
我做了一些性能测试来比较querydsl和jdbctemplate之间的开销/性能比较。
这是我做的
1.创建了一个使用querydsl和jdbctemplate的spring boot项目
2.创建2个端点,1个用于使用querydsl,另一个用于jdbctemplate
3. querydsl配置使用spring boot autoconfigured数据源来配置其SQLQueryFactory。
4. JdbcTemplate也使用相同的自动配置数据源自动配置
5.存储库中有两个类似查询的实现,一个使用querydsl,另一个使用jdbctemplate。查询相对复杂,由几个内部联接和where子句组成
6. Service方法有一个for循环,并在每次迭代中调用repository方法。迭代次数是可配置的,并且已设置为100,000次迭代
7. System.nanoTime()用于控制器中的服务方法,以计算执行存储库方法的多次迭代所花费的时间。
8. JdbcTemplate平均花费800毫秒来执行100,000个存储库调用
9. Querydsl平均花费5000毫秒来执行100,000次存储库调用
的 10。观察:对于同一查询,Querydsl比JdbcTemplate慢6倍。开销大概是在querydsl的查询序列化中。
QueryDSL存储库实现
List<Customer> customers = new ArrayList<>();
Customer customerObj = null;
List<Tuple> customerTuples =queryFactory.select(customer.firstName,customer.status,customer.customerId).
from(customer).innerJoin(customerChat).on(customer.customerId.eq(customerChat.senderId)).
innerJoin(customerChatDetail).on(customerChat.chatDetailId.eq(customerChatDetail.chatDetailId)).
where(customerChatDetail.isRead.eq(true).and(customer.status.eq(true))).fetch();
for (Tuple row : customerTuples) {
customerObj = new Customer();
customerObj.setFirstName(row.get(customer.firstName));
customerObj.setStatus( row.get(customer.status));
customerObj.setCustomerId(row.get(customer.customerId));
customers.add(customerObj);
}
return customers;
JdbcTemplate Implementation
List<Customer> customers = this.jdbcTemplate.query(
"select first_name,status,customer_id from customer inner join v_customer_chat on customer.customer_id=v_customer_chat.sender_id inner join v_customer_chat_detail on v_customer_chat.chat_detail_id = v_customer_chat_detail.chat_detail_id where v_customer_chat_detail.is_read = ? and customer.status = ?;",new Object[] {true, true},
new RowMapper<Customer>() {
public Customer mapRow(ResultSet rs, int rowNum) throws SQLException {
Customer customer = new Customer();
customer.setFirstName(rs.getString("first_name"));
customer.setStatus(rs.getBoolean("status"));
customer.setCustomerId(rs.getLong("customer_id"));
return customer;
}
});
基本上我试图用不同的库做同样的事情并测量哪一个会产生更多的开销 1.使用连接执行相对复杂的查询 2.从结果集中填充bean。
我正在使用H2内存数据库。数据库只保存每个表的几个记录。和1个与查询匹配的结果行。
该方法在for循环中执行(1万亿次迭代)。并且在循环周围的System.nanoTime()的帮助下计算时间。
它是一个具有不同端点的spring引导项目(一个用于querydsl,另一个用于jdbctemplate)。 querydsl和queryfactory的配置如下:
@Autowired
public DataSource dataSource;
@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource);
}
@Bean
public com.querydsl.sql.Configuration querydslConfiguration() {
SQLTemplates templates = H2Templates.builder().build();
com.querydsl.sql.Configuration configuration = new com.querydsl.sql.Configuration(templates);
configuration.setExceptionTranslator(new SpringExceptionTranslator());
return configuration;
}
@Bean
public SQLQueryFactory queryFactory() {
Provider<Connection> provider = new SpringConnectionProvider(dataSource);
return new SQLQueryFactory(querydslConfiguration(), provider);
}
答案 1 :(得分:1)
配置您的应用,查看查询中花费的时间。它是查询的解析和编译,还是查询本身?
您是在编写返回整个域对象还是列子集的查询(使用JPA“select new BlaBlaDTO”类型构造)?
您是否考虑过使用Spring Data JPA,您可以完全控制是否要使用RAW SQL,命名查询或Spring Data JPAs方法命名约定查询?
您的JDBC连接是否设置为在数据库端缓存预准备语句,以便只需为具有不同参数的相同查询准备一次(这会产生巨大差异)?
您使用的是第一级和第二级缓存来提高服务器端性能吗?
选择原始JDBC作为首选机制最终会变得非常糟糕;复杂查询,没有脏检查,没有乐观锁定等。
答案 2 :(得分:0)
Ammen.M如果您正在寻找数据库访问方面的性能(在JavaEE平台中),最好的选择是纯JDBC,但是每个人都知道它的局限性以及字符串与本机SQL的广泛使用。 Spring Data,JPA或QueryDSL,所有这些框架都为您提供了其他好处,如类型安全,表和对象之间的关系映射。
所以,如果你的团队真的关心应该是你的赌注。