ResultSet和Select * Performance

时间:2009-07-24 16:54:08

标签: java oracle spring jdbc resultset

我正在重构一些Spring JDBC代码,其中一些成本较高的查询执行“SELECT * FROM ...” - 并且即将开始检查实际需要哪些列而只是 SELECT x,y FROM .. 他们。但阅读 ResultSet 类似乎大多数数据都是延迟加载的。当你执行 ResultSet.next()时,它会移动数据库中的光标(此应用程序中的Oracle 10g),当你执行 ResultSet.getXX()时,它会检索到柱。所以我的想法是,如果你做一个“SELECT *”,但只检索你想要的列,你并没有真正受到性能影响。我正确地考虑了这个吗?我能想到的唯一可以解决这个问题的地方就是在数据库中,因为它将查询结果存储在内存中并且必须使用更多内存,如果只选择了几行,那么它实际上只会存储指向那些命中了查询的列甚至不是这种情况。

思想?

注意:这仅适用于标准 ResultSet ,我知道 CachedResultSet 的行为方式不同。

6 个答案:

答案 0 :(得分:6)

如果从“SELECT *”到“SELECT A,B,C”给你带来任何有意义的性能提升,我会感到惊讶,除非你有大量你不需要的列。

这完全取决于您的数据库,驱动程序和应用程序,而且大多数概括都将毫无意义。

你将从中获得的唯一可靠答案是通过基准测试 - 尝试“SELECT *”,尝试“SELECT A,B,C”,看看是否有值得追逐的改进。

答案 1 :(得分:4)

根据表结构,Oracle版本和所涉及的索引,完全有可能更改您选择的列集将通过更好地更改查询计划来显着提高性能。对于大多数查询,性能优势可能很小,但总体而言,明确命名列通常是一种很好的做法。

当您拥有优化程序可以使用的“覆盖索引”时,将会出现性能提高的最简单情况。如果您选择的所有列和您要过滤的所有列都是单个索引的一部分,则该索引是查询的覆盖索引。在这种情况下,Oracle可以避免从表中读取数据,并且可以只读取索引。

在其他情况下,性能也会得到改善。如果您有查询,则优化程序可能能够执行table elimination,这些临时连接不会影响最终输出。如果要选择所有列,则无法进行优化。如果您有包含链接行的表,则删除列也可以消除获取已删除列所在的其他块的需要。如果表中有LONG和LOB列,则不选择这些列也会带来很大的改进。

最后,消除列通常会减少Oracle在通过线路传输之前对结果进行排序和哈希所需的空间量。即使ResultSet可能会懒散地在应用程序服务器的RAM中加载数据,它也可能无法通过网络懒惰地获取列。如果从表中选择所有列,则JDBC驱动程序可能必须一次获取至少1个完整行(更有可能是每个网络往返获取10或100行)。由于驱动程序不知道何时获取数据将要求哪些列,您必须通过网络发送所有数据。

答案 2 :(得分:3)

我知道在我参与的应用程序中,大数据量(和大表格大小)从选择* 变为选择x,y 确实购买了我们小的性能提升。但是,我强烈建议您使用分析工具(例如Oracle的内置分析器或外部分析器),并使用大型数据集来规范化噪声(如网络流量,硬盘旋转,太阳点)等等)

答案 3 :(得分:3)

在我工作的环境中,SELECT *通常从未使用过。我相信skaffman&对于性能增益很小,aperkins可能是正确的。这是作为数据库开发人员之一,我强烈认为你应该总是命名你正在检索的列,但我想这可能没有真正的基础。

嗯...我想,从可维护性的角度来看,人们可能会争辩说,命名要检索的列可以自行记录您的代码。 SELECT *不会给另一个开发人员提供尽可能多的信息来处理这个问题。是否&小的性能优势证明了我不确定的额外打字。

答案 4 :(得分:3)

我和@skaffman以及其他人在一起 - 充其量只是微不足道的收获。如果您考虑Oracle如何检索数据并记住它的块I / O,那么无论您在客户端中要求哪些列,数据库都将获取整个块,无论如何都会找到该记录。如果您的客户端总是检索整个记录(例如,在SQL * Plus中执行SELECT *),那么可能会有性能提升,但是在您只需要传输数据的情况下,那么可能并不多。< / p>

“SELECT *”对于编译的应用程序来说可能是邪恶的。如果表格发生变化,您的代码可能会中断。这就是为什么我不会使用它。

编辑:仔细考虑所有优秀的回复:

  1. Justin对可能出现重大性能改善的某些情况提出了很好的观点。
  2. Codemonkey提出了关于自我记录代码的好处。
  3. Aperkins和Skaffman提出了最好的建议之一:尝试一下,测量并根据自己的情况看看效果如何。
  4. + 1's四周...... 我没看到的是有人摔倒自己建议使用“SELECT *”。如果您可以轻松指定所需的确切列,我会修复代码。

答案 5 :(得分:1)

在切换语句时,我从未注意到彼此之间的任何性能提升 - 我相当确定Oracle无论如何都会首先抓取整行的内容,无论通配符或列规范如何。在此之前要检查的性能有很大的因素(索引,硬盘速度等)。

作为一种编码习惯,我会避免使用“SELECT *”。指定特定列确实使每个查询的意图更加明显。它可以提供良好的自我记录代码。写出列名也有助于我了解我计划用查询做什么,因为我正在编写它。