5

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

想法?

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

4

6 回答 6

6

如果从 "SELECT *" 到 "SELECT A,B,C" 给您带来任何有意义的性能改进,我会感到惊讶,除非您有大量不需要的列。

这一切都非常依赖于您的数据库、驱动程序和应用程序,并且大多数概括都将毫无意义。

您将从中获得的唯一可靠答案是对其进行基准测试 - 尝试“SELECT *”,尝试“SELECT A,B,C”,看看是否有值得追求的改进。

于 2009-07-24T16:58:20.240 回答
4

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

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

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

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

于 2009-07-24T18:03:27.300 回答
3

我确实知道,在我参与的应用程序中,在从select *更改为select x 的大数据量(和大表大小)下,y确实为我们带来了一点性能提升。但是,我强烈建议您像 skaffman 一样使用分析工具,例如 Oracle 的内置分析器或外部分析器,并使用大型数据集来规范化噪声(如网络流量、硬盘驱动器旋转、太阳黑点) , ETC)

于 2009-07-24T17:02:32.650 回答
3

在我工作过的环境中,通常不会使用 SELECT *。我相信 skaffman 和 aperkins 关于性能增益很小的说法可能是正确的。这是作为数据库开发人员的其中一件事,我强烈认为您应该始终命名要检索的列,但我想这可能没有真正的基础。

嗯...我想,从可维护性的角度来看,有人可能会争辩说,命名您正在检索的列有助于对您的代码进行自我记录。SELECT * 不会为其他开发人员提供尽可能多的信息以供后续使用。我不确定这是否以及小的性能优势是否证明了额外的打字是合理的。

于 2009-07-24T17:07:36.323 回答
3

我与@skaffman 和其他人在这方面 - 充其量是微不足道的。如果您考虑 Oracle 如何检索数据并记住它是块 I/O,那么无论您在客户端中要求的列是什么,数据库都会获取找到记录的整个块。如果您的客户端总是检索整个记录(例如,在 SQL*Plus 中执行 SELECT *),则可能会提高性能,但在您的情况下,只有在您请求时才传输数据,那么可能不会太多。

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

编辑:在这里仔细考虑所有优秀的回应:

  1. 贾斯汀对某些可以显着提高性能的情况提出了很好的看法。
  2. Codemonkey 提出了关于自记录代码的好观点。
  3. Aperkins 和 skaffman 提出了最好的建议之一:尝试一下,测量一下,看看你自己的情况会产生什么效果。

+1 无处不在...我看不到有人会自暴自弃地推荐使用“SELECT *”。如果很容易指定您需要的确切列,我会修复代码来执行此操作。

于 2009-07-24T17:09:49.093 回答
1

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

作为一种编码实践,我会避免使用“ SELECT *”。指定特定列确实使每个查询的意图更加明显。它提供了良好的自记录代码。写出列名也有助于我在编写查询时了解我计划对查询执行的操作。

于 2009-07-24T20:04:50.567 回答