由我们手工创建的Java对象关系管理器发出的大型(1400万行)表上的select *
经常挂起。
import org.mountsinai.foo.Entity;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
// aDataSource is defined ...
NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(aDataSource);
RowMapper<Entity> entityRowMapper = (ResultSet rs, int rowNum) -> {
Entity entity = new Entity();
entity.setDatabaseId(rs.getInt("id"));
entity.setEntityId(rs.getString("entity_id"));
entity.setFound(rs.getBoolean("found"));
// Set 10 more fields ...
return entity;
};
jdbcTemplate.query("select * from table;", entityRowMapper);
因此我们使用NamedParameterJdbcTemplate
的查询(String sql,RowMapper rowMapper)方法,我们使用com.microsoft.sqlserver:mssql-jdbc
的JDBC库。
查询将转到SLQ Server数据库。有时一切正常,尤其是当表很小时。但是当表很大(1400万行)时,jdbcTemplate.query
经常挂起。在这种情况下,SQL Server Profiler对数据库的跟踪显示查询finished,正如我们所看到的
SP:StmtCompleted
RPC:Completed
EventClass
是跟踪中的it。客户端不会引发异常。
我正在考虑尝试修复这个问题,方法是用PagingAndSortingRepository
接口中使用Pageable的findAll
调用替换间歇性失败的代码。
亚瑟
1条答案
按热度按时间pqwbnv8z1#
进行分页可能会解决这个问题,但是您不必为此使用JPA,也不会有什么帮助。
正如在评论中所讨论的,你的问题很可能是在内存中存储1400万个示例需要大量内存,当然,构建这些示例需要大量时间。
因此,分页可以通过将过程分解为块来帮助实现,但是使用当前的方法,只需将偏移量和限制合并到查询中,就可以轻松地实现这一点。
但是在大型表上分页可能会变慢,使用key based pagination可能会更有效,其中您选择按主键排序的每批n行,并在下一批中选择前一批最后一个id值之后的前n行。
一个可能效果更好的替代方法是使用
RowCallbackHandler
代替行Map器,在处理下一行之前完全处理一行。这样可以最大限度地减少内存中保存的数据,同时只运行一个查询。当然,这取决于您尝试如何处理所有数据,如果这是一个可行的方法。如果您要进行分页,您可能需要了解Spring Batch,它是为这种处理而设计的。
JPA可能只是增加了每行的内存和性能成本,它通常不太适合处理如此大量的数据。