ResultSet:按索引检索列值与按标签检索

时间:2008-10-09 11:18:50

标签: java optimization jdbc resultset maintenance

使用JDBC时,我经常遇到像

这样的结构
ResultSet rs = ps.executeQuery();
while (rs.next()) {
    int id = rs.getInt(1);
    // Some other actions
}

我问自己(以及代码的作者)为什么不使用标签来检索列值:

int id = rs.getInt("CUSTOMER_ID");

我听到的最好的解释是关于表现的。但实际上,它是否会使处理速度极快?我不相信,尽管我从未进行过测量。即使通过标签检索会慢一点,但在我看来,它提供了更好的可读性和灵活性 那么有人可以给我很好的解释,避免通过列索引而不是列标签来检索列值吗?这两种方法的优点和缺点是什么(可能是关于某些DBMS)?

13 个答案:

答案 0 :(得分:56)

警告:我会在这里夸夸其谈,因为这让我发疯了。

99%*的时间,这是一个荒谬的微观优化,人们有一些模糊的想法让事情“变得更好”。这完全忽略了这样一个事实:除非你一直处于数百万个SQL结果的非常紧张和繁忙的循环,这很有可能是罕见的,你永远不会注意到它。对于那些没有这样做的人来说,维护,更新和修复列索引中的错误的开发人员时间成本远远大于您的无限应用程序性能较差的硬件增量成本。

不要对这样的优化进行编码。维护它的人的代码。然后观察,测量,分析和优化。再次观察,再次测量,再次分析,再次优化。

优化几乎是开发的最后一步,而不是第一步。

*图组成。

答案 1 :(得分:45)

默认情况下,您应该使用字符串标签。

<强>优点:

  • 列顺序的独立性
  • 更好的可读性/可维护性

<强>缺点:

  • 您无法控制列名(通过存储过程访问)

您更喜欢哪种?

整数?

  

int i = 1;
   customerId = resultSet.getInt(i ++);
   customerName = resultSet.getString(i ++);
   customerAddress = resultSet.getString(i ++);

或Strings?

  

customerId = resultSet.getInt(“customer_id”);
   customerName = resultSet.getString(“customer_name”);
   customerAddress = resultSet.getString(“customer_address”);

如果在第1位插入新列怎么办?您更喜欢哪种代码?或者,如果更改了列的顺序,您需要更改哪个代码版本?

这就是为什么你应该默认使用字符串标签。

答案 2 :(得分:6)

答案已被接受,尽管如此,这里还有一些我尚未看到的其他信息和个人经验。

通常使用列名(常量而不是文字),如果可能的话。这样更清晰,更易于维护,未来的更改不太可能破坏代码。

但是,列索引有一个用途。在某些情况下,这些更快,但不够充分,这应该覆盖名称*的上述原因。在开发处理ResultSet的工具和一般方法时,这些非常有价值。最后,可能需要索引,因为该列没有名称(例如未命名的聚合)或者有重复的名称,因此没有简单的方法来引用它们。

*请注意,我已经编写了一些JDBC驱动程序并查看了一些开放源代码,并在内部使用列索引来引用结果列。在我使用的所有情况下,内部驱动程序首先将列名映射到索引。因此,您可以轻松地看到列名称在所有这些情况下总是需要更长时间。但对于所有司机来说可能并非如此。

答案 3 :(得分:5)

来自java文档:

  

ResultSet接口提供了getter方法(getBoolean,getLong等),用于从当前行检索列值。可以使用列的索引号或列的名称来检索值。通常,使用列索引会更有效。列从1开始编号。为了获得最大的可移植性,每行中的结果集列应按从左到右的顺序读取,每列应只读一次。

当然,每个方法(命名或索引)都有它的位置。我同意命名列应该是默认值。但是,在需要大量循环的情况下,以及在代码(或类)的同一部分中定义和维护SELECT语句的情况下,索引应该没问题 - 建议列出所选的列,而不仅仅是“SELECT * FROM ...”,因为任何表更改都会破坏代码。

答案 4 :(得分:4)

当然,使用列名可提高可读性并简化维护。但使用列名称有另一面。如您所知,SQL允许多个具有相同名称的列名称,不能保证您在resultSet的getter方法中键入的列名实际上指向您要访问的列名称。理论上,使用索引号而不是列名是优先的,但它会降低可读性......

由于

答案 5 :(得分:2)

我认为使用标签不会影响性能。但是还有另一个原因是不使用String。或者int,就此而言。

考虑使用常量。使用int常量可使代码更易读,但也不太可能出错。

除了更具可读性之外,常量还可以防止您在标签名称中输入拼写错误 - 如果您这样做,编译器将抛出错误。任何有价值的IDE都会捡起它。如果您使用Stringints

,则情况并非如此

答案 6 :(得分:2)

我在Oracle数据库上对这个确切的主题进行了一些性能分析。在我们的代码中,我们有一个包含大量列和大量行的ResultSet。在请求执行方法的20秒(!)中,oracle.jdbc.driver.ScrollableResultSet.findColumn(String name)大约需要4秒。

显然整体设计有问题,但使用索引代替列名可能需要4秒钟。

答案 7 :(得分:2)

你可以充分利用两者!使用索引的速度与使用列名的可维护性和安全性。

首先 - 除非你通过结果集循环,否则只使用列名。

  1. 定义一组整数变量,每个变量对应一个您要访问的列。变量的名称可以包括列的名称:例如iLast_Name。

  2. 在结果集循环之前迭代通过列元数据并将每个整数变量的值设置为相应列名的列索引。如果'Last_Name'列的索引为3,则将'iLast_Name'的值设置为3.

  3. 在结果集循环中,使用GET / SET方法中的整数变量名称。对于正在访问的实际列名,变量名是开发人员/维护者的直观线索,但值是列索引,将提供最佳性能。

  4. 注意:初始映射(即列名到索引映射)仅在循环之前完成一次,而不是循环中的每个记录和列。

答案 8 :(得分:1)

JDBC驱动程序负责索引查找的列。因此,如果每次驱动程序进行查找(通常在哈希映射中)时都按列名提取值,则检查列名称的相应索引。

答案 9 :(得分:0)

我同意以前的答案,即表现不会强迫我们选择任何一种方法。最好考虑以下事项:

  • 代码可读性:对于每个开发者来说,阅读代码标签比索引更有意义。
  • 维护:考虑SQL查询及其维护方式。在修复/改进/重构SQL查询后,更有可能发生这种情况:更改提取的列的顺序或更改结果列名称。对我来说,改变提取的列的顺序(作为在结果集中添加/删除新列的结果)更有可能发生。
  • 封装:尽管您选择的方式尝试隔离运行SQL查询的代码并在同一组件中解析结果集,并且只让该组件了解列名及其到索引的映射(如果您决定使用它们。)

答案 10 :(得分:0)

使用索引是一种优化尝试。

开发人员需要额外的努力来查看必要的数据,以检查他们的代码在更改后是否能正常工作,从而节省了时间。

我认为这是我们使用数字而不是文本的内在本能。

答案 11 :(得分:0)

除了在Map中查找标签外,它还会导致额外的String创建。虽然它会在堆栈上发生,但它仍然会带来成本。

这一切都取决于个人选择,直到日期我只使用了索引: - )

答案 12 :(得分:0)

正如其他张贴者所指出的那样,除非您有确凿的理由不这样做,否则我会坚持使用列名。与例如查询优化相比,性能的影响可以忽略不计。在这种情况下,维护比小优化更为重要。