优化 ResultSet 获取性能(Apache Spring、MySQL)
Posted
技术标签:
【中文标题】优化 ResultSet 获取性能(Apache Spring、MySQL)【英文标题】:Optimizing ResultSet fetch performance (Apache Spring, MySQL) 【发布时间】:2012-05-08 16:41:39 【问题描述】:我的问题是:我试图通过来自 mysql 的 JDBCTemplate 在 Spring 中处理大约 150 万行数据。有这么多的行,我正在使用建议的 RowCallbackHandler 类here
代码实际上可以工作,但是速度很慢...问题是,无论我将提取大小设置为多少,每次提取似乎都会获得大约 350 条记录,提取之间有 2 到 3 秒的延迟(从观察我的日志)。我尝试注释掉 store 命令并确认行为保持不变,所以问题不在于写入。
有 6 列,只有 1 列是 varchar,而那一列只有 25 个字符长,所以我看不出吞吐量是问题。
理想情况下,我希望一次获得更多 30000-50000 行。有没有办法做到这一点?
这是我的代码:
protected void runCallback(String query, Map params, int fetchSize, RowCallbackHandler rch)
throws DatabaseException
int oldFetchSize = getJdbcTemplate().getFetchSize();
if (fetchSize > 0)
getJdbcTemplate().setFetchSize(fetchSize);
try
getJdbcTemplate().query(getSql(query), rch);
catch (DataAccessException ex)
logger.error(ExceptionUtils.getStackTrace(ex));
throw new DatabaseException( ex.getMessage() );
getJdbcTemplate().setFetchSize(oldFetchSize);
and the handler:
public class SaveUserFolderStatesCallback implements RowCallbackHandler
@Override
public void processRow(ResultSet rs) throws SQLException
//Save each row sequentially.
//Do NOT call ResultSet.next() !!!!
Calendar asOf = Calendar.getInstance();
log.info("AS OF DATE: " + asOf.getTime());
Long x = (Long) rs.getLong("x");
Long xx = (Long) rs.getLong("xx");
String xxx = (String) rs.getString("xxx");
BigDecimal xxxx = (BigDecimal)rs.getBigDecimal("xxxx");
Double xxxx = (budgetAmountBD == null) ? 0.0 : budgetAmountBD.doubleValue();
BigDecimal xxxxx = (BigDecimal)rs.getBigDecimal("xxxxx");
Double xxxxx = (actualAmountBD == null) ? 0.0 : actualAmountBD.doubleValue();
dbstore(x, xx, xxx, xxxx, xxxxx, asOf);
【问题讨论】:
【参考方案1】:您的查询是什么?尝试为您正在搜索/排序的字段创建 indexex。这会有所帮助。
第二种策略:在内存缓存中实现。或者使用休眠加二级缓存。
这两种技术都可以显着加快您的查询执行速度。
【讨论】:
for #1 只是在表上做一个 select *,所以没有排序索引不会帮助 #2 更改 dbs 不是一个选项 内存缓存不需要你改变数据库 对于内存缓存实现,您将拥有一些带有延迟初始化集合的服务(如果您只是在没有任何位置/顺序的情况下进行选择)。首次执行时使用您的查询结果初始化此集合,其他调用只需从内存中设置结果。【参考方案2】:几个问题
直接查询数据库需要多长时间。另一个问题可能是应用程序和数据库主机之间的 ASYNC_NETWORK_IO 延迟。
你没用Spring检查过吗
【讨论】:
对不起,我以为我拥有它,但我没有。我不认为是这样,但我如何检查 ASYNC_NETWORK_IO? SQLServer 提供 DMV 来查询等待类型,如这里 confio.com/db-resources/sql-wait-types/async-network-io 但我不知道 mysql 中的等价物是什么。如果您直接从控制台查询,您是否检查过需要多长时间?这应该让您公平地了解客户端应用程序是否存在问题。然后您可以检查是网络还是 Spring 导致了问题【参考方案3】:答案实际上是执行 setFetchSize(Integer.MIN_VALUE) 虽然这完全违反了 Statement.setFetchSize 的规定合同,mysql java 连接器使用此值来流式传输结果集。这会带来巨大的性能提升。
修复的另一部分是我还需要创建自己的 (Spring) JdbcTemplate 子类,以适应负提取大小...实际上,我在这里举了代码示例,在那里我首先找到了设置的想法fetchSize(Integer.MIN_VALUE)
http://javasplitter.blogspot.com/2009/10/pimp-ma-jdbc-resultset.html
感谢两位的帮助!
【讨论】:
以上是关于优化 ResultSet 获取性能(Apache Spring、MySQL)的主要内容,如果未能解决你的问题,请参考以下文章
一次性获取`java.sql.ResultSet`行中的所有值