【问题标题】:Performance issue in using SELECT *? [duplicate]使用 SELECT * 时的性能问题? [复制]
【发布时间】:2010-10-04 00:10:56
【问题描述】:

可能重复:
Which is faster/best? SELECT * or SELECT column1, colum2, column3, etc
What is the reason not to use select *?

使用 SELECT * 而不是 SELECT FiledName, FiledName2 ... 是否存在任何性能问题?

【问题讨论】:

  • 这可能符合“最重复的 SO 问题”的条件。 :>D

标签: sql database performance


【解决方案1】:

应该是的。我在工作中全心全意地告诉我,我永远不应该使用 SELECT *。事实上,我们的政策是不使用它,因为 a) 这意味着仅通过查看查询就可以使用的内容和可用的内容不明确,并且 b) 它速度较慢,因为 SQL 服务器必须找到它需要的每一列并返回它们.

然而,我从未见过任何证据。

编辑:另外,如果存储过程在服务器上编译并使用 SELECT *,当底层表结构发生变化时据说它不会选择返回新的在 SQL 将 SELECT * 编译为单个列时引入了列。

【讨论】:

  • 两者之间没有查询计划差异,但如果表获得了额外的列,则查询不会像原来那样执行,它返回的数据可能比可能需要的多。
  • 无论您明确命名它们还是使用 *.在您想要所有列的情况下,性能是相同的。但是,禁止 * 会迫使您考虑从数据库中真正需要什么,这是一种很好的做法。
【解决方案2】:

唯一的性能问题是您的应用程序只需要select * 返回的字段子集。数据库中没有性能差异,因为它们实际上是相同的。

【讨论】:

  • +1 - 这在回答这个问题时经常被忽略。如果只有三个名为 col1、col2 和 col3 的列,SELECT col1, col2, col3SELECT * 是相同的。
【解决方案3】:

我不了解计算性能,但就读取/维护能力(即人类性能)而言,我们不在我的商店使用 select *。一切都是明确选择的。

【讨论】:

    【解决方案4】:

    如果指定了所有字段,则不,在性能方面不应该存在有意义的差异。但是,如果您只想要一个有十几个列的表中的几个特定字段,那么它会更慢。

    SELECT * 存在可读性和可维护性问题。始终使用特定的字段名称是有意义的,即使您想选择所有字段。

    【讨论】:

      【解决方案5】:

      SELECT * 在运行之前被转换为 SELECT Field1 , Field2 .... 等,因此它们实际上是相同的。性能上没有区别。

      但是,当它的 SELECT Field1 , Field2 .. 时,可读性和可维护性更好。

      【讨论】:

        【解决方案6】:

        如果您需要列的子集,那么您对优化器的帮助很差(不能选择索引,或者不能只去索引,...)

        某些数据库可以选择仅从索引中检索数据。那件事非常有帮助,并且提供了令人难以置信的加速。运行 SELECT * 查询不允许这个技巧。

        无论如何,从应用的角度来看并不是一个好的做法。


        示例:

        • 您有一个包含 20 列(C1、C2、...、C19 C20)的表 T。
        • 您在 T 上有一个 (C1,C2) 的索引
        • 你让SELECT C1, C2 FROM T WHERE C1=123
        • 优化器拥有索引的所有信息,不需要去表数据

        如果你SELECT * FROM T WHERE C1=123,优化器需要获取所有列数据,那么(C1,C2)上的索引就不能使用了。

        多个表的连接非常有用。

        【讨论】:

        • 我认为索引只与 JOIN、WHERE 和 GROUP BY 子句相关。如果我错了,有人可以纠正我,但是 select 子句中的列如何阻止优化器选择索引?
        • @Princess 我已经用一个例子更新了帖子
        【解决方案7】:

        每次执行 select * 时,is 可能会额外查询来获取列列表。在高事务环境中,这可能成为可见的开销,但时不时地进行一次不会有任何影响。

        此外,在插入记录时,切勿在插入时使用 select *,以防添加列。

        【讨论】:

        • 我只是想问你——当你在选择表中明确指定一个字段时,服务器会检查该字段是否真的存在,所以还有额外的查询还是我错了?
        • 这并不完全准确(至少对于某些数据库而言),大多数顶级数据库都会为查询准备一个计划并缓存它,因此无论您使用 * 还是 col list 列的列表仍然是在计划编译时查询。当表发生 DDL 更改时,查询缓存失效。
        【解决方案8】:

        我不是 DBA,但从我记得从我们的 DBA 那里学到的东西,推理(至少对于 SQL Server)是 DB 缓存算法不能很好地缓存 '*' 查询,但如果你正在运行多次指定精确列的相同查询,它会很好地缓存。

        我确信知识渊博的 DBA 可以详细了解缓存机制的工作原理,但这就是性能下降的原因。

        注意:缓存性能仅在查询要运行多次时才有效,尤其是在很短的时间范围内,否则您将看不到性能差异。

        【讨论】:

          【解决方案9】:

          从技术上讲,这取决于您使用的关系数据库管理系统。我认为性能影响将是微秒。如果您绝对想从系统中挤出最后一点性能,我会说不要使用它们。

          我个人一直都在使用它。

          【讨论】:

            【解决方案10】:

            【讨论】:

            • 这篇文章更多地与可维护性有关,而不是性能。我同意该帖子的答案,即 select * 是一种反模式,但这个问题是关于性能以及是否存在差异。
            【解决方案11】:

            如果您只使用字段的子集,则性能差异可能很大。请参见以下示例,其中涉及从 CScoutanalysis of the Linux code 检索 1,411,771 行。

            $ time sh -c "echo 'select * from IDS' | mysql cslinux >/dev/null"
            real    0m5.622s
            user    0m2.580s
            sys     0m0.532s
            
            $ time sh -c "echo 'select EID from IDS' | mysql cslinux >/dev/null"
            real    0m4.492s
            user    0m0.716s
            sys     0m0.096s
            

            这甚至没有衡量对服务器的性能影响。

            【讨论】:

            • 不错。我想为了获得“公平”的结果,您应该在第二个 select 语句中包含多于一列。
            • 事实上,他应该命名表上的所有字段以进行公平测试。
            • 指定所有字段后,应该没有明显的性能差异(开销只是获取表列的名称)。
            【解决方案12】:

            如果您将 sql 嵌入代码中,那么为了清楚起见,您应该始终使用长格式,而不是性能。对于临时查询,选择 * 语法的效率基本上不低于指定列名,除非您有大量列,除非您进行非规范化,否则您不应该这样做。

            我应该得到 1 分,因为在一个句子中使用了 2 个除非它仍然有意义! :)

            【讨论】:

              【解决方案13】:

              性能,不多。只是有点笨拙:在一个表中,比如说,有 10 列,连接到其他两个表甚至更多,特别是对于大型结果集,SELECT * 可以返回数十列,通常包含大部分未使用甚至无用的数据。就对 DBMS 的影响而言,不会有太多影响,但所有数据仍然需要以某种方式通过网络传输;网络带宽和随之而来的延迟肯定会增加。我在大容量环境中亲眼目睹了这一点。这绝对很重要。

              除了带宽问题之外,您还可能遇到模棱两可的列命名问题(消除歧义通常意味着无论如何都要删除 SELECT *,所以您最好从一开始就这样做),而且明确说明也是一种很好的做法代码里面的代码需要;这样做在很多方面都有帮助——调试、协作等。

              【讨论】:

                【解决方案14】:

                SELECT * 需要 SQL 来查找所有列名,但这并不是长期影响最大的性能。

                SELECT * 语句对性能的最大影响是当您执行需要非聚集索引来评估的查询时。即使非聚集索引是每一列的覆盖索引,SQL 仍然会查找主键并从聚集索引中获取值。

                除此之外,如果您只需要一两列,由于返回的结果集比所需的大,您将面临网络瓶颈。

                【讨论】:

                  【解决方案15】:

                  我将回应其他人所说的关于“select *”检索列列表作为请求处理的一部分。相比之下,您还可以按序号选择列,这样可以节省更多时间,因为 RDBMS 引擎甚至不需要查找列来确定要检索的列的位置。我发现这对于聚合查询非常有用。

                  例如:select count(1) from ... 与 select count(*) from ...

                  在这个例子中,RDBMS 只需要知道它需要第一列的计数,ZING,它是关闭的。在(不幸的是)更常见的选择计数(*)中,RDBMS 检索所有列的列表,然后验证每一行以确定它是否对计数有效(而不是仅验证第一列)。

                  这在大多数情况下都很有效。我很确定大多数数据库系统都会在计数中计算 NULL 值,但您应该注意这一点并在假设之前进行验证。

                  YMMV、禁止的地方无效等!

                  【讨论】:

                    【解决方案16】:

                    性能 如果您不需要所有列,这总是很糟糕。返回比需要更多的数据会限制数据库和您的局域网/广域网带宽。

                    可读性 知道哪些列在视图中,过程可能非常有用,SELECT * 根本没有帮助,我认为它会适得其反。

                    *测试 如果您进行架构更改,所有在 中使用 SELECT * 的代码都应该失效,因为您为检查元数据而编写的任何测试都应该检查视图的输出,proc。

                    *当然,假设您已经完成了所有优秀数据库开发人员都应该具备的测试:)

                    【讨论】:

                      【解决方案17】:

                      如果您在连接中使用 select *,那么您会自动发送比您需要的更多信息,因为连接字段会重复。这是对处理时间和网络资源的浪费,并可能导致性能问题。进一步不指定字段意味着您的应用程序可能会在添加新字段时中断,特别是如果它们是用户不打算看到但用于审计或数据库类型处理的字段。在插入中选择 * 总是一个坏主意,因为某些不太聪明的人实际上可能会改变表中列的顺序。

                      【讨论】:

                        【解决方案18】:

                        我同意几乎所有的答案,除了某些性能声明。如果您实际上要使用表中的所有列,我认为 SELECT * 版本要快一点。原因如下:

                        在 (id,x) 上有唯一索引的表上执行这两个查询:

                        SELECT x,y,z,w FROM tab WHERE id='abc' ORDER BY s
                        
                        SELECT x,y,z,w FROM tab WHERE id='abc' 
                        AND x in ('a','b','c','d','e','f','g','h',...)
                        ORDER BY ('a','b','c','d','e','f','g','h',...)
                        

                        哪个更快?如果 'x in' 子句将表中 x 的所有值命名为 id 'abc',那么第一个查询可能会更快。现在让我们重命名这些字段:

                        SELECT field_name, field_type, field_offset, field_len
                        FROM internal_field_catalog
                        WHERE table_name = 'abc'
                        ORDER BY field_order
                        

                        因此,在检索数据时,SELECT * 允许引擎执行(相当于)单个 memcpy 以将行数据移动到结果集中,并且在检索字段数据时,它可能会更快地被选中。

                        我要说的是有一个极端情况,SELECT * 非常有用并且可能更快。您可能总是需要表中的所有列的一个原因是在 RDBMS 中存储对象持久性时(出于某种原因)。每个经验法则都有一个例外。

                        【讨论】:

                        • 我接受这一点,但我认为“不使用它”的其他原因与此示例使用 SELECT * 相悖。
                        【解决方案19】:

                        也许吧。这在很大程度上取决于数据库引擎、它如何存储内容、返回多少行、还有多少其他列以及其他列的大小。

                        如果您使用的是基于行的数据库(即大多数),它将所有列存储在一起(几乎所有列都这样做,除了通常单独存储的 BLOB,尤其是较大的),那么执行 SELECT * 几乎没有对服务器本身的影响 - 它必须获取整行。

                        另一方面,如果您通过网络发送数据(甚至在本地发送数据,因为它会影响使用的缓冲区的大小等),那么减少列可能会有所帮助,因为这样会更少要发回的字节。如果查询有任何困难(例如需要 IO),那么服务器性能无论如何都可能使这种差异相形见绌。

                        如果行中有大块,则 SELECT * 不是很聪明 - 否则,它不太可能产生太大影响,但可以。

                        有一些“基于列”的数据库引擎在四处游荡——它们完全不同——对它们来说,“SELECT *”是一个总的性能杀手;一定要避免它。很有可能,如果您使用的是一个,那么您会完全意识到这一点(通常它们用于非常大的数据仓库应用程序)。

                        对我来说,不使用“SELECT *”的主要优点是可维护性。当有人向表中添加额外的列时,您不会感到惊讶;当有人删除您正在使用的列之一时,您的查询“快速失败”。它使代码更具自我记录性,因为有人可以随便看到您想要的列。

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 2011-08-16
                          • 2015-04-10
                          • 1970-01-01
                          • 2012-03-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多