ResultSet:按索引检索列值与按标签检索
在使用JDBC的时候,我经常碰到类似的构造
ResultSet rs = ps.executeQuery(); while (rs.next()) { int id = rs.getInt(1); // Some other actions }
我问自己(还有代码的作者)为什么不使用标签来检索列值:
int id = rs.getInt("CUSTOMER_ID");
我听到的最好的解释是有关性能。 但实际上,它是否使处理速度非常快? 我不这么认为,尽pipe我从来没有做过测量。 即使通过标签检索会慢一点,但是,在我看来,它提供了更好的可读性和灵活性。
那么有人可以给我一个很好的解释,避免检索列索引,而不是列标签? 这两种方法的优点和缺点是什么(也许,关于某些DBMS)?
你应该使用默认的string标签。
优点:
- 列顺序的独立性
- 更好的可读性/可维护性
缺点:
- 您无法控制列名(通过存储过程访问)
你更喜欢哪个?
整型?
int i = 1;
customerId = resultSet.getInt(i ++);
customerName = resultSet.getString(i ++);
customerAddress = resultSet.getString(i ++);
或string?
customerId = resultSet.getInt(“customer_id”);
customerName = resultSet.getString(“customer_name”);
customerAddress = resultSet.getString(“customer_address”);
那么如果在位置1插入一个新的列呢? 你更喜欢哪个代码? 或者,如果列的顺序发生了变化,您需要更改哪个代码版本?
这就是为什么你应该默认使用string标签。
警告:我要在这里得到夸耀,因为这让我疯狂。
99%的时间,这是一个荒谬的微观优化,人们有一些模糊的想法使事情变得更好。 这完全忽略了这样一个事实:除非你一直处于数百万个SQL结果的非常紧密和繁琐的循环之中,否则你永远都不会注意到这一点。 对于那些不这样做的人来说,维护,更新和修复列索引中的错误的开发人员的时间成本远远高于无限小的性能较差的应用程序的硬件增量成本。
不要像这样编码优化。维护它的人的代码。 然后观察,测量,分析和优化。 再观察一次,再次测量,再分析,并再次优化。
优化几乎是开发的最后一步,而不是第一步。
*图组成。
答案已被接受,无一例外,这里还有一些额外的信息和个人经验,我还没有看到。
一般情况下,使用列名(常量而不是文字是首选),如果可能的话。 这是更清晰,更容易维护,未来的变化不太可能打破代码。
但是,列索引是有用的。 在某些情况下,这些速度会更快,但是这不足以覆盖名称*的上述原因。 这些在开发处理ResultSet
的工具和一般方法时非常有价值。 最后,索引可能是必需的,因为该列没有名称(例如未命名的聚合)或名称重复,因此没有简单的方法来引用两者。
*请注意,我已经编写了一些JDBC驱动程序,并在内部查看一些开放源代码,并在内部使用列索引来引用结果列。 在我使用过的所有情况下,内部驱动程序首先将列名映射到索引。 因此,您可以很容易地看到,在所有这些情况下,列名总是需要更长的时间。 尽pipe这可能不是所有的司机。
当然,使用列名可以提高可读性并使维护变得简单。 但使用列名有一个反面。 如您所知,SQL允许具有相同名称的多个列名称,但不能保证在resultSet的getter方法中键入的列名称实际上指向您要访问的列名称。 从理论上讲,使用索引号而不是列名是有好处的,但是会降低可读性。
谢谢
从java文档:
ResultSet接口提供getter方法(getBoolean,getLong等)以从当前行中检索列值。 可以使用列的索引号或列的名称检索值。 一般来说,使用列索引会更有效率。 列从1开始编号。为了获得最大的可移植性,应该按照从左到右的顺序读取每行中的结果集列,并且每列只能读取一次。
当然,每个方法(命名或索引)都有它的位置。 我同意命名的列应该是默认的。 但是,在需要大量循环的情况下,以及在同一段代码(或类)中定义和维护SELECT语句的情况下,索引应该是可以的 – build议列出被select的列,而不仅仅是“SELECT * FROM …”,因为任何表更改将打破代码。
我不认为使用标签会影响性能。 但还有一个不使用String
的原因。 或者int
s,就此而言。
考虑使用常量。 使用int
常量会使代码更易读,但也不太可能出错。
常数还可以防止你在标签名称中input错字,如果你这样做,编译器会抛出一个错误。 而任何值得的任何IDE都会把它捡起来。 如果你使用String
或者ints
,情况就不一样了。
我在Oracle数据库上对这个确切的主题做了一些性能分析。 在我们的代码中,我们有一个ResultSet,它有许多列和很多行。 在20秒(!)请求执行方法oracle.jdbc.driver.ScrollableResultSet.findColumn(String name)需要大约4秒。
显然,整体devise有些问题,但是使用索引而不是列名可能需要4秒钟的时间。
JDBC驱动程序负责处理索引查询。 因此,如果每次驱动程序进行查找(通常在哈希映射中),都按列名提取值,以检查列名称的相应索引。
你可以有两个最好的! 使用索引的速度与使用列名的可维护性和安全性。
首先 – 除非你循环通过一个结果集只使用列名称。
-
定义一组整数variables,每个列将为您访问一个。 variables的名称可以包含列的名称:例如iLast_Name。
-
在结果集循环之前迭代通过列元数据,并将每个整数variables的值设置为相应列名称的列索引。 如果“Last_Name”列的索引是3,则将“iLast_Name”的值设置为3。
-
在结果集循环中使用GET / SET方法中的整数variables名称。 variables名是开发人员/维护人员对正在访问的实际列名称的视觉线索,但值是列索引,并且会给出最佳性能。
注意:初始映射(即列名称到索引映射)只在循环之前执行一次,而不是循环中的每个logging和列。
我同意以前的答案,performance不是强迫我们select任何一种方法。 相反,考虑下面的事情是很好的:
- 代码可读性:对于每个开发者来说,阅读你的代码标签比索引更有意义。
- 维护:考虑SQL查询和维护的方式。 在修复/改进/重构SQL查询之后,更有可能发生的情况是:更改提取的列的顺序或更改结果列的名称。 在我看来,改变提取列的顺序(作为在结果集中添加/删除新列的结果)具有更大的可能性发生。
- 封装:尽pipe你select的方式尝试隔离在同一个组件中运行SQL查询和parsing结果集的代码,并只让这个组件知道列名称及其对索引的映射(如果你决定使用它们)。
使用索引是一个优化的尝试。
由此节省的时间被开发人员花费额外的精力来查找必要的数据来检查他们的代码是否会在更改后正常工作。
我认为这是我们内在的使用数字而不是文本的本能。
除了在Map中查找标签外,还会导致额外的String创build。 虽然它会发生在堆栈上,但它仍然会带来成本。
这一切都取决于个人的select,直到date我只使用索引:-)