StringBuilder和ResultSet性能问题的可能原因是什么

时间:2010-02-02 15:10:59

标签: java xml performance jdbc stringbuilder

我在Java中循环使用ResultSet;出于测试目的,每行返回约30行,每列有17列(所有字符串数据)。我正在使用StringBuilder从结果中手动构建XML String,并且它实际上花了大约36秒来完成这些迭代。

注意:我意识到这不是从数据库中获取XML的最佳方式,甚至是从ResultSet中获取XML的最佳方法 - 但这让我对无论如何性能缓慢感到好奇。

更新:根据目前的回复,我必须解决以下问题: 运行Query的时间不到一秒,我在我的代码的每个部分之前和之后都做了一个System.currentTimeMillis()来缩小它。 36秒完全在下面的代码中。

ResultSetMetaData rsmeta = rset.getMetaData();
StringBuilder resultBuilder = new StringBuilder();
resultBuilder.append("<?xml version=\"1.0\" ?><ROWSET>");
if(numColumns != 0){   
   while (rset.next()) {
      resultBuilder.append("<ROW>");
      for (int i = 0; i <= numColumns -1;i++) {
         columnName = rsmeta.getColumnName(i+1);
         resultBuilder.append("<");
         resultBuilder.append(columnName);
         resultBuilder.append(">");
         resultBuilder.append(rset.getString(i+1));
         resultBuilder.append("</");
         resultBuilder.append(columnName);
         resultBuilder.append(">");
      }
      resultBuilder.append("</ROW>");
      numRows += 1;
   }
}
else {
   stmt.close();
   wsConn.close();
   return "No Results";
}

更新:根据我收到的建议 - 此代码大约花费相同的时间或花费半秒钟。

StringBuilder resultBuilder = new StringBuilder();
resultBuilder.append("<?xml version=\"1.0\" ?><ROWSET>");
if(numColumns != 0){   
   while (rset.next()) {
      resultBuilder.append("<ROW>");
      for (int i = 0; i <= numColumns -1;i++) {
         //columnName = rsmeta.getColumnName(i+1);
         resultBuilder.append("<");
         resultBuilder.append("TestColumnName");
         resultBuilder.append(">");
         //resultBuilder.append(rset.getString(i+1));
         resultBuilder.append("TestData");
         resultBuilder.append("</");
         resultBuilder.append("TestColumnName");
         resultBuilder.append(">");
      }
      resultBuilder.append("</ROW>");
      numRows += 1;
   }
}
else {
   stmt.close();
   wsConn.close();
   return "No Results";
}  

我确实消除了其他一切的最后一个测试是用实际的迭代次数替换while测试(160,我之前完成的小测试返回的最大行数)。现在的问题是,这个结果集会导致如此缓慢的结果。

while (numRows <= 160) {
// same as above
}

更新:正如建议的那样,我将关闭此问题,因为标题并未反映出问题所采用的方向。

9 个答案:

答案 0 :(得分:6)

我认为你的笔记2单独说话。

时间不会在StringBuilder中丢失,但在其他地方......


columnName = rsmeta.getColumnName(i+1);

根据实施情况,读取元数据可能会非常缓慢。 您只能为所有resultSets读取它们一次,并在循环中重复使用它们。


<强>更新

从上次更新开始,StringBuilder无关紧要,问题出在ResultSet上。我觉得问题标题和给出的所有答案都与你当前的关注点不一致 我建议关闭这个问题,并为新的关注开启一个新的问题: - )

答案 1 :(得分:5)

我强烈怀疑与从数据库访问和检索数据所花费的时间相比,StringBuilder是您的瓶颈。优化简单字符串连接并没有显着改变运行时间这一事实证实了这一点。

您需要优化访问数据库的方式 - 更快地连接到数据库,压缩连接等。

但是,我可以为您的代码提供一个微优化:不添加像“&lt;”这样的单字符字符串,而是添加一个字符,例如'&lt;'。然而,这应该没有太大的差别。

答案 2 :(得分:3)

我非常怀疑StringBuilder是罪魁祸首。 Java广泛使用它,我已经广泛使用它,我已经为我自己的JVM重写它,基本上它总是能够以每秒数亿的速度吃掉字符。

我认为您的麻烦来自数据库访问本身。当您运行查询并获得ResultSet时,并不一定意味着已获取所有数据并将其内部转换为易于管理的内存表示形式。根据数据库实现(及其JDBC驱动程序),ResultSet可能是许多结果的 promise ,这些结果在ResultSet.next()和{{1}时动态获取调用方法。

尝试简单地浏览结果,调用所有ResultSet.getString()next(),但不将获得的数据存储在getString()中。如果它仍然需要36秒,那么StringBuilder是无辜的(我坚信这是)。

答案 3 :(得分:2)

实际上,使用getColumnName()从结果集中读取信息,next()和getValue()通常需要更多的时间,而不是首先获取结果。对于不可滚动的结果集尤其如此。

StringBuilder以指数方式分配内存(newSize = FACTOR * oldSize),因此您执行的操作越多,重新分配所需的内容就越少。

要真正对此进行测试,只需将 rset rsmeta 替换为具有相同方法的虚拟对象:let next()为实际行数返回true让其他方法返回实际长度的字符串。

答案 4 :(得分:2)

问题是ResultSet有一个到数据库的持久链接,并在被调用时获得更多信息。我建议您查看CachedRowSet(javadoc here)。它会立即下拉所有数据,其行为与ResultSet完全相同。然后,您可以关闭数据库连接,然后开始解析数据。我建议尝试一下,看看它是否加快了你的过程。

答案 5 :(得分:2)

检查您是如何获得结果集的。声明中有一些方法允许您更改ResultSet如何提取数据。

特别是,看看

答案 6 :(得分:1)

我同意StringBuilder可能不是这里的实时接收器。但是,StringBuffer可能会受到轻微限制,因为它最终必须在缓冲区增长时分配额外的空间(并超过它的默认大小)。这个建议解决了你的问题,但我再次怀疑他们会解决你的问题。

祝你好运

答案 7 :(得分:1)

尝试用固定数据替换各种调用。例如,有人建议访问元数据是罪魁祸首。尝试更换:

columnName = rsmeta.getColumnName(i+1);

使用:

columnName = "Column" + i;

其中i是一个int,你在循环之前设置为0并通过循环递增。

答案 8 :(得分:0)

昨天我遇到了类似的问题:查询大约170万条记录的Microsoft SQL Server 10并读取这些值大约需要50分钟。改变后;大约80秒......

我的问题是使用的jdbc驱动程序:唯一的变化是从com.microsoft.sqlserver.jdbc 1.2版驱动程序到net.sourceforge.jtds版本1.2.2驱动程序...