小编典典

为什么SELECT *被认为有害?

sql

为什么是选择SELECT *?如果添加了想要的新列,这是否意味着更少的代码更改?

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


阅读 60

收藏
2021-04-07

共1个答案

小编典典

确实有三个主要原因:

将数据转移到消费者方面效率低下。 当您选择SELECT *时,通常从数据库中检索到的列数超出了应用程序实际需要运行的列数。这将导致更多数据从数据库服务器移至客户端,从而减慢访问速度并增加计算机上的负载,并花费更多时间在网络上传输。当有人向原始使用者编码其数据访问权时不存在且不需要的基础表中添加新列时,尤其如此。

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

绑定问题。当您选择时,可以从两个不同的表中检索两个具有相同名称的列。这通常会使您的数据使用者崩溃。想象一下一个将两个表联接在一起的查询,两个表都包含一个称为“ ID”的列。消费者如何知道哪个是哪个?当基础表结构发生更改时,SELECT 还会使视图(至少在某些版本的SQL Server中)混乱(不重建视图,并且返回的数据可能是无用的)。最糟糕的是,您可以随心所欲地为列命名,但是下一个出现的家伙可能无法知道他必须担心添加会与您已经开发的列发生冲突的列名称。

但这对SELECT *并非全无好处。我将它们自由地用于以下用例:

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

表示“一行”时。 在以下用例中,SELECT 很好,并且有传言称它是性能杀手,只是城市传说,它可能已经在很多年前生效,但现在不行了:

SELECT COUNT(*) FROM table;

在这种情况下,表示“对行进行计数”。如果要使用列名代替,它将计算该列的值不为null的行。对我来说,COUNT(*)真正使您理解了对行进行计数的概念,并且避免了因从集合中消除NULL而导致的奇怪边缘情况。

这种类型的查询也是如此:

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

在任何值得盐分的数据库中,仅表示“一行”。放在子查询中的内容无关紧要。有些人在SELECT列表中使用b的ID,否则他们将使用数字1,但是IMO这些约定几乎是荒谬的。您的意思是“计算行数”,这就是的含义。那里的大多数查询优化器足够聪明地知道这一点。(尽管说实话,我只知道这对于SQL Server和Oracle是正确的。)

2021-04-07