java-ResultSet:按索引检索列值与按实验室检索
使用JDBC时,我经常遇到类似
ResultSet rs = ps.executeQuery();
while (rs.next()) {
int id = rs.getInt(1);
// Some other actions
}
我问自己(也包括代码作者)为什么不使用标签来检索列值:
int id = rs.getInt("CUSTOMER_ID");
我听到的最好的解释是关于性能的。 但是实际上,这是否会使处理速度非常快? 我不相信,尽管我从未进行过测量。 我认为,即使按标签检索会稍慢一些,但它仍具有更好的可读性和灵活性。
因此,有人可以给我很好的解释,避免使用列索引而不是列标签来检索列值吗? 两种方法的优缺点(也许与某些DBMS有关)是什么?
13个解决方案
56 votes
警告:我要在这里大吃一惊,因为这会让我发疯。
99%*的时间里,人们有一些模糊的想法使事情“变得更好”,这是一个荒谬的微观优化。 这完全忽略了一个事实,除非您一直处于一个极其紧密和忙碌的循环中,以百万计的SQL结果一直存在,而这是罕见的,但您永远不会注意到它。 对于每个不这样做的人来说,开发人员在列索引中维护,更新和修复错误的时间成本远远大于性能持续恶化的应用程序所需的硬件增量成本。
不要在其中编写优化代码。维护人员的代码。 然后观察,测量,分析和优化。 再次观察,再次测量,再次分析,然后再次优化。
优化几乎是开发的最后一步,而不是第一步。
*图已组成。
Cowan answered 2020-01-28T14:00:42Z
46 votes
默认情况下,您应该使用字符串标签。
优点:
列顺序的独立性
更好的可读性/可维护性
缺点:
您无法控制列名(通过存储过程访问)
你更喜欢哪个?
整数?
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插入新列怎么办? 您想要哪种代码? 或者,如果更改了列的顺序,则完全需要更改哪个代码版本?
这就是为什么您应该默认使用字符串标签的原因。
Martin Klinke answered 2020-01-28T14:00:03Z
6 votes
答案仍然被接受,不过,这里有一些我尚未看到的其他信息和个人经验。
一般情况下,如果可能,请使用列名(首选常量而不是文字)。 这既更清楚,更易于维护,而且将来的更改也不太可能破坏代码。
但是,有用于列索引的用途。 在某些情况下,这些速度更快,但不足以覆盖上述*原因。 这些在开发用于处理2722646169380980979712的工具和通用方法时非常有价值。 最后,可能需要索引,因为该列没有名称(例如未命名的聚合)或名称重复,因此没有简单的方法可以同时引用这两个名称。
*请注意,我已经编写了一些JDBC驱动程序,并浏览了一些开放源代码,并且在内部使用列索引来引用结果列。 在我使用过的所有情况下,内部驱动程序都首先将列名映射到索引。 因此,在所有这些情况下,您都可以轻松地看到列名将始终花费更长的时间。 但是,并非所有驱动程序都适用。
Kevin Brock answered 2020-01-28T14:01:17Z
6 votes
从Java文档中:
ResultSet接口提供用于从当前行检索列值的getter方法(getBoolean,getLong等)。 可以使用列的索引号或列的名称来检索值。 通常,使用列索引会更有效。 列从1开始编号。为了实现最大的可移植性,应按从左到右的顺序读取每一行中的结果集列,并且每一列只能读取一次。
当然,每种方法(命名或索引)都有其位置。 我同意命名列应为默认列。 但是,在需要大量循环以及在代码(或类)的同一部分中定义和维护SELECT语句的情况下,索引应该可以-建议列出正在选择的列,而不仅仅是列出 “ SELECT * FROM ...”,因为任何表更改都会破坏代码。
Jason answered 2020-01-28T14:01:47Z
4 votes
当然,使用列名可以提高可读性并简化维护。 但是使用列名有一个缺点。 如您所知,SQL允许多个具有相同名称的列名,但不能保证您在resultSet的getter方法中键入的列名实际上指向您要访问的列名。 从理论上讲,可以使用索引号代替列名,但这会降低可读性...
谢谢
answered 2020-01-28T14:02:13Z
2 votes
我认为使用标签不会对性能产生太大影响。 但是还有另一个原因不使用Strings。 或intss。
考虑使用常量。 使用String常量可使代码更易读,但也不太可能出错。
除了更具可读性之外,该常量还阻止您在标签名称中输入错字-如果这样做,编译器将引发错误。 任何有价值的IDE都可以使用。 如果使用Strings或ints,则不是这种情况。
Sietse answered 2020-01-28T14:02:43Z
2 votes
我针对这个确切的主题在Oracle数据库上进行了一些性能分析。 在我们的代码中,我们有一个ResultSet,其中包含许多列和大量行。 在20秒(!)中,请求执行方法oracle.jdbc.driver.ScrollableResultSet.findColumn(String name)大约需要4秒。
显然,总体设计存在问题,但是使用索引代替列名可能要花4秒钟的时间。
answered 2020-01-28T14:03:09Z
2 votes
您可以两者兼得! 使用索引的速度以及使用列名的可维护性和安全性。
首先-除非您遍历结果集,否则仅使用列名。
定义一组整数变量,每一个要访问的列都一个。 变量的名称可以包括列的名称:例如 iLast_Name。
在结果集循环之前,请遍历列元数据,并将每个整数变量的值设置为相应列名的列索引。 如果“ Last_Name”列的索引为3,则将“ iLast_Name”的值设置为3。
在结果集循环中,在GET / SET方法中使用整数变量名称。 变量名是开发人员/维护人员在访问实际列名时的直观提示,但值是列索引,将提供最佳性能。
注意:初始映射(即列名到索引的映射)仅在循环之前执行一次,而不是对循环中的每个记录和列进行一次。
Rick Post answered 2020-01-28T14:03:52Z
1 votes
JDBC驱动程序负责列索引的查找。 因此,如果每次驱动程序进行查找时(通常在哈希图中)按列名提取值,以检查列名的相应索引。
zloster answered 2020-01-28T14:04:12Z
0 votes
我同意先前的回答,即性能不能迫使我们选择这两种方法。 最好考虑以下事项:
代码可读性:对于每个阅读代码标签的开发人员来说,其意义远胜于索引。
维护:考虑一下SQL查询及其维护方式。 在修复/改进/重构SQL查询之后,更可能发生的情况是:更改提取的列的顺序或更改结果列的名称。 在我看来,更改提取列的顺序(作为在结果集中添加/删除新列的结果)更有可能发生。
封装:尽管您选择了哪种方式,请尝试在运行SQL查询的代码之间进行隔离,并在同一组件中解析结果集,并仅使该组件知道列名及其到索引的映射(如果您决定使用它们) )。
Cha2lenger answered 2020-01-28T14:04:47Z
0 votes
使用索引是对优化的尝试。
这样节省的时间浪费了开发人员花费大量精力来查找必要的数据,以检查其代码在更改后是否可以正常工作,从而浪费了时间。
我认为使用数字而不是文本是我们的固有本能。
databyss answered 2020-01-28T14:05:16Z
0 votes
除了在Map中查找标签外,它还会导致额外的String创建。 虽然它会在堆栈上发生,但仍然会带来成本。
这完全取决于个人选择,直到现在我只使用了索引:-)
Vinod Singh answered 2020-01-28T14:05:41Z
0 votes
正如其他张贴者所指出的那样,除非您有确凿的理由不这样做,否则我会坚持使用列名。 与例如查询优化相比,性能的影响可以忽略不计。 在这种情况下,维护比小优化更为重要。
Rober2D2 answered 2020-01-28T14:06:02Z