原文自国外技术社区dzone,作者为 Javin Paul,[传送门]https://dzone.com/articles/why-you-should-not-use-select-in-sql-query-1)
我在网上阅读过许多文章,人们都在说在 sql 查询中使用 select * 是一个不好的习惯并且开发者应该避免这种事情发生。除此之外,我们应该始终需要明确查询出的列。这是一个很好的建议并且也是我在教授初级开发者中的一个最佳 sql 事例,但是大部分人都没有解释这背后的原因。
除非你向那些 sql 开发人员解释并列出原因为什么不应该在查询中使用 select *,否则很难说服他们,特别是对那些在 oracle 数据库中从 EMP 执行 select * 来学习 sql 的人来说。
在这篇文章中,我将尝试通过给出一些实际的原因来填补这一差距,来阐述为什么在查询中使用 select * 是一个馊主意。
这里有几个原因可以解释为什么不应该在 sql 查询中使用 select * from table。
1. 不必要的 I/O 操作(输入输出)
通过使用 select *,可以返回那些被忽略的而且你并不需要的数据,但是获取这些数据并非没有消耗的。这会在数据库中产生不必要的IO消耗,因为本身应该是从索引中读取数据但现在是从 page 中获取。
这也会使你的查询变慢。如果你尚不清楚查询是如何执行的,以及查询引擎是如何逐步执行你的查询的,我建议你阅读像 Markus Winand 的 SQL Performance Explained 或者 观看 Udemy 的 The Complete SQL BootCamp 来学习更多。
2. 增加网络流量负荷
select * 显然会比原本的需求返回更多的数据,并且,也会消耗更多的网络带宽。网络带宽的增加也意味着数据需要花费更长的时间才能到达客户端中,诸如像执行查询语句的查询工具 SQL Server Management Studio,Toad,oracle 的 SQL developer 或者 Java 应用服务器。
3. 更多的应用内存消耗
由于数据的增加,你的应用程序可能需要消耗更多的内存,来保存那些并不会使用但是来自于 Microsoft SQL Server 的不必要数据。
4. 取决于结果集中列的排序
当你在应用程序中使用 select * 并且不依赖列的顺序的时候,如果你添加新列或者改变表中列的顺序时,结果集的顺序也会因此改变。
5. 当在表中添加新列时视图会被破坏
在视图中使用 select * 时,如果添加了新列并且从表中删除了旧列,则会发生细微的错误。为什么会这样?那是因为你的视图不会中断,但会开始返回错误的结果。
为了防止事件发生,像在 SQL Server 中,你应该在视图中多使用 WITHSCHEMABINDING。这会阻止你在视图中使用 select *。
6. 在 join 查询中产生冲突
当你在 join 查询中使用 select *,如果数张表中存在诸如 status、active、name 等的名称的列时,会给查询带来复杂性。
在单一查询中,这没什么问题,但当你尝试使用其中的列来排序或者在 CTE、派生表中进行查询时,那时你就需要做一些调整了。
7. 从一张表复制数据到另一张表
当需要从一张表复制数据到另一张表,你在 insert .. select 语句中使用 select * 时,如果两张表中列的顺序不同,则可能会将不正确的数据复制不正确的列中。
有一些程序员会想,在 exists 语句中使用 selec * 比起 select 1 更快,因为查询解析器需要做额外的工作来校验静态至。
在很久之前这或许是对的,但在现在,解析器已经变得足够智能,在存在 exists 语句的情况下,select list 是毫无关系的。
结论
这就是所有原因关于为什么不能再在 sql 查询中使用 select * 了。在 select 查询中使用显式列列表总是比*(星号)通配符更好。不仅是因为这能够提高性能,而且也能使你的代码变得更可读。不仅如此,在我们对表中添加新列,特别是如果具有引用原始表的视图时,它也帮助我们创建可维护的代码,让事情变得顺畅。