sql - 为什么 SELECT * 被认为是有害的?

标签 sql database

为什么 SELECT * 是不好的做法?如果您添加了所需的新列,这是否意味着需要更改的代码更少?

我知道 SELECT COUNT(*) 是某些数据库的性能问题,但如果您真的想要每一列怎么办?

最佳答案

主要有以下三个原因:

  • 将数据移动到消费者时效率低下。当您选择 * 时,您通常会从数据库中检索比您的应用程序真正需要运行的列更多的列。这会导致更多数据从数据库服务器移动到客户端,从而减慢访问速度并增加计算机的负载,并花费更多时间通过网络传输。当有人向基础表添加新列时尤其如此,而这些新列在原始消费者对其数据访问进行编码时并不存在且不需要。

  • 索引问题。考虑这样一种情况,您希望将查询调优到高性能。如果您要使用 *,并且它返回的列比您实际需要的多,则服务器通常必须执行比其他方式更昂贵的方法来检索您的数据。例如,您将无法创建一个仅覆盖 SELECT 列表中的列的索引,即使您这样做了(包括所有列 [shudder]),下一个过来的人并向基础表添加一列会导致优化器忽略优化的覆盖索引,并且您可能会发现查询的性能会无缘无故地大幅下降。

  • 绑定(bind)问题。当您选择 * 时,可能会从两个不同的表中检索同名的两列。这通常会使您的数据消费者崩溃。想象一个连接两个表的查询,这两个表都包含一个名为“ID”的列。消费者怎么知道哪个是哪个?当基础表结构发生变化时,SELECT * 也会混淆 View (至少在某些版本的 SQL Server 中)——the view is not rebuilt, and the data which comes back can be nonsense .最糟糕的是,你可以随意命名你的专栏,但下一个出现的人可能无法知道他必须担心添加一个专栏会与你已经开发的冲突名字。

但这对 SELECT * 来说并非全是坏事。我在这些用例中大量使用它:

  • 临时查询。当尝试调试某些东西时,尤其是在我可能不熟悉的窄表中,SELECT * 通常是我最好的 friend 。它可以帮助我了解正在发生的事情,而不必对基础列名是什么进行大量研究。列名越长,“加号”就越大。

  • 当 * 表示“一行”时。在以下用例中,SELECT * 就可以了,关于它是性能 killer 的谣言只是都市传说,可能有一定的道理许多年前,但不是现在:

    SELECT COUNT(*) FROM table;
    

    在这种情况下,* 表示“计算行数”。如果您要使用列名而不是 * ,它将计算该列的值不为空的行。对我来说,COUNT(*) 确实让您明白了您正在计算 的概念,并且您避免了由于从聚合中消除 NULL 而导致的奇怪边缘情况。

    同样适用于这种类型的查询:

    SELECT a.ID FROM TableA a
    WHERE EXISTS (
        SELECT *
        FROM TableB b
        WHERE b.ID = a.B_ID);
    

    在任何值得称道的数据库中,* 仅表示“一行”。您在子查询中放入什么并不重要。有些人在 SELECT 列表中使用 b 的 ID,或者他们会使用数字 1,但在我看来,这些约定非常荒谬。你的意思是“计算行数”,这就是 * 的意思。大多数查询优化器都足够聪明,知道这一点。 (老实说,我只知道 SQL Server 和 Oracle 是这样。)

关于sql - 为什么 SELECT * 被认为是有害的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14759188/

相关文章:

c# - 清理数据库返回数据

mysql - 将 MySQL 表与其自身连接

mysql - SQL-phpmyadmin-外键错误号 : 150

mysql - 如何使用MySQL查询真子集?

sql - 在 psql 中选择每组前 5 个得分结果

java - Recyclerview 有条件点击

java - 使用 Processing 连接到 Microsoft Access 数据库

mongodb - 使用 $toLower 或 $toUpper 更新 MongoDB 集合

database - Postgres-XL : functions for JSON

sql - 在 PL/SQL 过程中,如何将表名作为参数传递?