【问题标题】:Hypothetical performance yield to not using SELECT *假设性能屈服于不使用 SELECT *
【发布时间】:2011-04-21 12:55:35
【问题描述】:

作为序言,我知道(你也应该知道!)在生产中使用SELECT * 是不好的,但我正在维护由其他人编写的脚本。而且,我也知道这个问题的细节很少……但假设的情况。

假设我有一个从包含 20 个字段的表中选择所有内容的脚本。假设是典型的客户信息。

假设我是一名优秀的开发人员,我将我在显示端实际使用的 13 个特定字段中的 SELECT * 缩短为 SELECT

通过明确列出字段与SELECT * 相比,我可以获得什么类型的性能优势(如果有)?

我会这么说,两个查询都利用了相同的精确索引。如果您想知道,更具体的查询无法访问其他查询无法使用的覆盖索引。

我并不期待奇迹,例如添加针对更具体查询的索引。我只是想知道。

【问题讨论】:

    标签: sql database theory


    【解决方案1】:

    您为什么不自己尝试一下并告诉我们?

    这一切都取决于列的数量和宽度。

    更好的是,您有实际的性能问题吗?告诉我们您的实际问题是什么并向我们展示代码,然后我们可以提出潜在的改进建议。与担心 SELECT * 与 SELECT 字段列表相比,可能还有其他改进要好得多。

    【讨论】:

      【解决方案2】:

      我希望看到的主要区别是网络流量减少。如果任何一列很大,它们可能需要时间来转移,如果不显示它们当然是完全浪费。

      如果您的数据库库按索引(而不是名称)引用列,这也很重要,因为如果数据库中的列顺序发生更改,则会破坏代码。

      编码风格明智,它允许您查看其余代码将使用哪些列,而无需阅读它。

      【讨论】:

        【解决方案3】:

        这取决于三件事:您的数据库使用的底层存储和检索机制、您遗漏的 7 列的性质以及结果集中返回的行数。

        如果您遗漏的 7 列(或任何数量)是“检索起来很便宜”的列,并且返回的行数很低,那么我预计不会有什么好处。如果列是“昂贵的”(例如,它们很大,或者它们是需要引用另一个从不缓存的文件的 BLOB)和/或您正在检索很多行,那么您可以期待显着的改进。多少取决于在您的特定数据库中检索该信息并在内存中组装的成本。

        顺便说一句,除了速度之外,还有其他原因在检索信息时使用命名列,这与绝对知道某些列包含在结果集中并且这些列按照您想要使用它们的所需顺序有关.

        【讨论】:

          【解决方案4】:

          嗯,在一个简单的实验中,我对它产生的巨大差异感到惊讶。

          我只是做了一个简单的查询,包含三个变体:

          1. 选择 *
          2. 选择作为主键的字段。 (它可能会直接从索引中获取这个而不实际读取记录)
          3. 选择一个非关键字段。

          我使用了一个包含大量字段的表——其中 72 个——包括一个 CLOB。该查询只是 where 子句中带有一个条件的选择。

          结果:

          运行*键非键 1 .647 .020 .028 2 .599 .041 .014 3 .321 .019 .027 平均 .522 .027 .023

          关键与非关键似乎并不重要。 (这让我很吃惊。)但是只检索一个字段而不是 select * 节省了 95% 的运行时间!

          当然,这是一张桌子的小实验。可能有很多很多相关的因素。我当然不是说不使用 select * 总是会减少 95% 的运行时间!但它比我预期的要令人印象深刻。

          【讨论】:

          • 您是否尝试先运行非键或键查询,以确保与“*”相比,它们没有缓存优势?令人惊讶的是差异如此之大。
          • 考虑到非键列在运行 2 中的返回速度比键列快得多(假设这不是错字)我认为缓存与速度的某些差异有关。
          • @Jonathan:我以不同的顺序多次运行它们,以避免由于缓存而产生误导性结果。我连续运行了两次,看看第二次是否会得到不同的结果,等等。除了缓存之外,另一个明显的问题是同时访问数据库还发生了什么。我当然不会声称我的结果是确定性的——只是很有趣。
          • @Larry:由于密钥和非密钥之间的差异很小,我认为这很可能只是您经常遇到的那种随机抽样错误,而且两者实际上差不多。请注意,键上的第二个数字是推动其平均值上升的原因。我查看了解释计划,它说它正在对所有文件进行全文件顺序读取——我的选择标准是在一个我认为没有索引的字段上,我必须检查一下。也许在某个范围内搜索关键字段会得到不同的结果。
          • 在我看来,包含 CLOB 可能是差异的主要来源。这可能会迫使它转到另一个文件或区域。我将不得不对没有 CLOB 的文件重复实验。
          【解决方案5】:

          在比较 13 和 20 个字段时,如果遗漏的 7 个字段不是 CLOB/BLOB 等字段,我预计不会看到明显的性能提升。

          I/O 是主要的数据库瓶颈(大多数数据库系统都受 I/O 限制),因此您可能认为您会将执行时间降低到原始查询执行时间的 13/20(因为您需要的数据要少得多) ,但是由于普通字段存储在相同的物理结构中(通常字段是连续排列的)并且文件系统读取整个块,因此您的磁头将读取相同数量的数据(假设所有 20 个字段都小于块大小;情况可以如果记录的大小大于文件系统的一个块,则更改)。

          SELECT *不好的原理还有一个原因——系统的稳定性。

          如果您在错误的地方使用SELECT *,那么对基础表的更改可能会意外破坏您的系统(通常是在以后发生,如果出现问题,最好早点破坏)。如果规范化数据(将列从一个表移动到另一个表,同时保持相同的名称),这可能特别有趣。在这种情况下,如果您在视图中链接SELECT *,并且如果您链接您的视图,那么您实际上可能不会收到任何错误,但(本质上)有不同的最终结果。

          【讨论】:

            【解决方案6】:

            选择 * 表示数据库必须花时间查找字段。如果您不需要所有这些字段(并且只要您有内部连接,您就不需要重复连接字段!)那么您就是在浪费服务器资源来获取数据和网络资源来传输数据。您还可能会浪费内存来保存记录集以使用它。虽然一个查询的性能改进可能很小,但该查询运行了多少次?使用这种极其糟糕的技术的人往往会在任何地方使用它,因此修复所有这些技术可能是一项重大改进,而无需付出太多努力。指定字段有多难?我不了解每个数据库,但在 SQL Server 中,我可以在几秒钟内从对象浏览器中拖放我想要的内容。因此,使用 select * 会在每次运行查询时用不到一分钟的开发时间换取更差的性能,并创建脆弱的代码,并且随着架构的变化而出现非常糟糕的问题。我认为没有理由在生产代码中使用 select *。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2019-09-09
              • 2023-04-11
              • 2022-09-30
              • 2015-08-03
              • 2012-11-10
              • 2022-05-03
              • 2013-06-25
              • 1970-01-01
              相关资源
              最近更新 更多