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

问题描述 投票:49回答:13

使用JDBC时,我经常遇到类似的结构

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

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

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

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

java optimization jdbc resultset maintenance
13个回答
46
投票

您应该默认使用字符串标签。

优点:

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

缺点:

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

你更喜欢哪个?

整型?

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

还是串?

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

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

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


0
投票

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

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

0
投票

使用索引是尝试优化。

开发人员查找必要的数据以检查他们的代码在更改后是否能正常工作所需的额外工作会浪费时间。

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


0
投票

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

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


0
投票

正如其他海报所指出的,我会坚持使用列名,除非你有一个非常有力的理由不这样做。与例如查询优化相比,对性能的影响可以忽略不计。在这种情况下,维护比小型优化更重要。


56
投票

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

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

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

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

*图组成。


6
投票

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

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

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

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


6
投票

从java文档:

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

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


4
投票

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

谢谢


2
投票

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

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

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


2
投票

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

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


2
投票

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

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

  1. 定义一组整数变量,每个变量对应一个您要访问的列。变量的名称可以包括列的名称:例如iLast_Name。
  2. 在结果集循环之前,通过列元数据进行迭代,并将每个整数变量的值设置为相应列名的列索引。如果'Last_Name'列的索引是3,则将'iLast_Name'的值设置为3。
  3. 在结果集循环中,使用GET / SET方法中的整数变量名称。对于正在访问的实际列名,变量名是开发人员/维护者的直观线索,但值是列索引,将提供最佳性能。

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


1
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.