为啥最后一次“ResultSet.next()”迭代比之前的迭代花费更多的时间?
Posted
技术标签:
【中文标题】为啥最后一次“ResultSet.next()”迭代比之前的迭代花费更多的时间?【英文标题】:Why does the last "ResultSet.next()"-iteration take way more time than the previous iterations?为什么最后一次“ResultSet.next()”迭代比之前的迭代花费更多的时间? 【发布时间】:2019-09-02 02:15:14 【问题描述】:我的“while(res.next())”循环的最后一次迭代需要 1.5 秒,而之前的迭代只需要大约 0,003 毫秒。我很困惑。
我从我的 SQLite 数据库中获取一个带有通用 JDBC 查询的 ResultSet。 ResultSet 并不大,它总是 4 列宽,0 到 100 行长。然后我想将 ResultSet 数据保存在 POJO 中,并将这些 POJO 存储在 ArrayList 中。我使用通常的迭代方法,您只需放置一个“while(res.next())”循环并迭代整个 ResultSet。我发现我的代码存在瓶颈,可以将其缩小到 while(res.next()) 循环。我开始调试并测量我的代码中的执行时间,结果发现最后一个 .next() 调用需要很长时间,它应该返回 false 以便循环停止。
ArrayList<Trade> trades = new ArrayList<>();
try
Statement statement = connector.getConnection().createStatement();
statement.setFetchSize(1337);
ResultSet res = statement.executeQuery("SELECT * FROM trades WHERE timestamp >= 0 AND timestamp < 1337;");
res.setFetchSize(1337);
int numberOfTrades = 0;
long startTime = System.nanoTime();
while(res.next())
long addObjectTime = System.nanoTime();
trades.add(new Trade(res.getLong("id"),res.getLong("timestamp"),res.getDouble("price"),res.getDouble("amount")));
numberOfTrades++;
System.out.println("Added trade to list within "+(System.nanoTime()-addObjectTime)+"ns.");
System.out.println("List-creation completed within "+(System.nanoTime()-startTime)+"ns.");
System.out.println("Number of trades: "+numberOfTrades);
catch (SQLException e)
e.printStackTrace();
这是我的代码。正如你所看到的,我已经尝试过使用各种 fetchSizes,正如其他人在有关 .next() 方法的性能线程中提到的那样。我尽我所能,但结果看起来仍然是这样的:
Added trade to list within 46000ns.
Added trade to list within 3200ns.
Added trade to list within 2400ns.
Added trade to list within 2300ns.
Added trade to list within 2300ns.
Added trade to list within 2300ns.
Added trade to list within 2300ns.
Added trade to list within 4500ns.
Added trade to list within 2300ns.
Added trade to list within 2300ns.
Added trade to list within 3100ns.
Added trade to list within 2400ns.
Added trade to list within 2300ns.
Added trade to list within 2300ns.
Added trade to list within 2400ns.
Added trade to list within 2400ns.
Added trade to list within 2300ns.
Added trade to list within 2200ns.
Added trade to list within 2300ns.
Added trade to list within 2300ns.
Added trade to list within 2300ns.
Added trade to list within 11100ns.
List-creation completed within 1548543200ns.
Number of trades: 22
使用 ResultSet 中的数据将 POJO 添加到我的 ArrayList 通常需要 2-5 微秒。所以总而言之,循环所花费的时间不应该比添加交易的所有执行时间长得多,对吧?在我的示例中,这将是 0,1073 毫秒。相反,循环总共需要超过 1.5 秒,这将是我预期的 10,000 倍。我实际上对这里发生的事情一无所知。这对我的程序来说是一个严重的问题,因为代码片段执行了大约 100,000 次,所以 150,000 秒将是 40 小时的性能损失:(
【问题讨论】:
您没有提及您的环境。这是使用分析器准确确定时间流向的理想场所。 可能是因为第一个 N-1 个结果已经发送,而最后一个结果需要额外的请求和发送。调查您的抓取大小。 @Gene 我给自己找了一个分析器,分析的结果是 JDBC3ResultSet.java:74 org.sqlite.core.NativeDB.step(long) 一直占用。我无法进一步了解该方法。我将尝试研究这一切。感谢您的意见。 @user207421 我也想过这个问题。但考虑到 OP 正在做什么,1.5 秒远非正常。 【参考方案1】:我实际上解决了这个问题,但我不是 100% 确定为什么现在解决了。我正在查询的数据库有数百万个条目,并且总是由单个列(时间戳)访问。我索引了时间戳,性能问题完全消失了。我仍然不知道为什么 .next() 方法的行为方式如此。
【讨论】:
哈哈。表的自然扫描顺序很早就命中了所有满足 WHERE 子句的条目。但是必须将所有行扫描到最后以验证是否没有更多行。索引将字段按排序顺序排列,因此只需扫描感兴趣的时间戳范围。然后扫描停止。 这基本上只是提醒“保持你的f *** in索引直”。有很多东西索引只是问题......我想你知道我的意思;)谢谢你的帮助我的朋友。以上是关于为啥最后一次“ResultSet.next()”迭代比之前的迭代花费更多的时间?的主要内容,如果未能解决你的问题,请参考以下文章
ResultSet.next 始终为 false,表格已填充