|
|
51CTO旗下网站
|
|
移动端

用Select * 进行SQL查询的七宗罪

本文通过在应用编程中的实际经验,向大家证明使用Select * from table进行SQL查询的“七宗罪”。

作者:陈峻编译来源:51CTO|2019-04-15 09:00

【51CTO.com快译】如今,网上许多文章都已明确地指出:使用“SELECT * ”作为SQL查询方式是一种极其危险的代码书写习惯。开发人员应该尽量在自己的程序中避免出现此类查询,取而代之的应该是明确地指定要查询的列名。不过,大家可能只是“知其然,而不知其所以然”。在本文中,让我向各位初级开发人员详细解释,此类SQL查询最佳实践背后的具体原因。

首先,我们经常面对的客观情况是:在Oracle数据库中,许多SQL开发人员都是从接触“SELECT * from EMP”(EMP为表的名称)之类的查询语句,开始学习SQL语言的。因此,除非能够给出充分的理由,否则我们很难撼动他们使用此类便捷查询语句的习惯。

下面,我将根据自己在应用编程中的实际经验,向大家证明使用Select * from table进行SQL查询的“七宗罪”。

1. 不必要的I/O(输入/输出)

通过使用SELECT * ,您虽然可以获得一些完全可以被忽略的返回数据,但是该获取过程可并不是免费的。那些本来可能只需要从索引页面中读取的数据检索,如今您却不得不从各个页面中以全量的方式读取出来。显然,此举会导致数据库端白白浪费各种有限的I/O周期。

另外,该方式也可能会拖慢您的查询速度。如果您好奇并想探究数据库后台的查询执行过程,以及查询引擎是如何顺次处理查询语句的话,我建议您参考:Markus Winand的《SQL Performance Explained》(请参见http://www.amazon.com/Performance-Explained-Everything-Developers-about/dp/3950307826/?tag=javamysqlanta-20),以及Udemy的《The Complete SQL BootCamp》(请参见https://click.linksynergy.com/fs-bin/click?id=JVFxdTr9V80&subid=0&offerid=323058.1&type=10&tmpid=14538&RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fthe-complete-sql-bootcamp%2F)课程。

2. 增加的网络流量

SELECT * 虽然能返回比用户预期白菜送彩金大全的数据,但是相应地,这些数据的传输势必会消耗白菜送彩金大全的网络带宽资源。与此同时,网络带宽的增加也就意味着:那些真正为用户所需要的数据将会花费更长的时间,才能被传送到客户端的应用程序上。例如:如果您可能是在本地计算机上运行由SQL Server Management Studio(请详见http://bit.ly/2CXPyBB)、Toad或SQL Developer for Oracle(请参见http://bit.ly/2xQzAsd)提供的查询编辑器,或是在某个Java应用服务器上运行此类查询,这都会耗费您不少的网络流量与资源。

3.白菜送彩金大全的应用内存

随着业务数据的猛增,您的应用程序可能需要使用白菜送彩金大全的内存,来保存由此类查询方式所产生的,可能来自Microsoft SQL Server(请参见http://www.java67.com/2018/01/top-4-free-microsoft-sql-server-books.html)的各种无用数据。

4.产生依赖于列排序的结果集(ResultSet)

当您在应用程序中使用SELECT * 查询后,您会得到一些依赖于数据表的列排序的结果集。因此,一旦有新的列被添加,或者是列排序被修改了,它们都会对查询的结果集产生不同的影响。

5.新增列会破坏既有的视图

如果您在视图(请参见http://www.java67.com/2012/11/what-is-difference-between-view-vs-materialized-view-database-sql.html)中使用了SELECT * ,那么一旦有新的列被添加,同时旧的列从表中被去除时,您所构建的原有视图就会被破坏,进而返回给用户错误的结果。

为避免此类情况的发生,您应该始终在SQL Server数据库(请参见http://javarevisited.blogspot.sg/2013/11/difference-between-char-varchar-nchar-nvarchar-sql-database.html#axzz5CSnhvSWV)里,对于视图的定义中,包含WITH SCHEMABINDING选项。

6. 连接查询中的冲突

如果您在连接查询(JOIN Query,请参见art/201904/https://javarevisited.blogspot.com/2012/11/how-to-join-three-tables-in-sql-query-mysql-sqlserver.html#axzz5az3hfsHW)中使用了SELECT * ,那么一旦在多个表中出现了具有相同名称的列,例如status、active和name等,就可能会产生各种并发式的冲突。

虽说在直接查询中,出现问题的可能性不大,但是当您试着按其中的某一列进行排序、或是在公用表表达式(Common Table Expression,CTE)、以及派生表(derived table)中使用查询的时候,您就需要进行各种进一步的调整,以避免产生冲突了。

7.在表间复制数据时的风险

您可能会经常使用“SELECT * into INSERT . . .”之类的语句,以实现将某些数据从一张表复制到另一张表。如果在两张表中,各个列的排列顺序略有不同,那么就可能会出现将不正确的数据复制到错误列中的情况。

一些程序员可能会认为:由于查询解析器必须额外地验证某些静态值,因此导致了在EXISTS语句(译者注:即检验查询的结果是否返回数据,请参见https://javarevisited.blogspot.com/2016/01/sql-exists-example-customers-who-never-ordered.html)中使用SELECT * 要比SELECT 1的速度更快一些。此观点搁在过去可能会有几分道理。但是现在,各种数据库解析器已经发展得相当白菜送彩金59网站大全了,它们判断EXISTS语句的效率,与产生SELECT结果列表(请参见art/201904/https://javarevisited.blogspot.com/2016/04/how-to-convert-result-of-select-command-to-comma-separated-String-in-SQL-Server.html)将毫无关系。

结论

通过上述七点分析,相信您应该明白了为什么不能在SQL查询中滥用SELECT * 的原因吧?可见,您应该尽可能地在查询中,使用显式的列名称,而不是那些星号通配符。此举不但能够提高您的代码效率,也可以使您的程序更加清晰。与此同时,该方法还能够帮助您创建各种具有可维护性的代码。而且,如果后期在表中有新的一列被添加的话,您的代码也不会因此受到影响,您仍然会拥有来自原始数据表的参考视图。

原文标题:7 Reasons Why Using SELECT * FROM TABLE in SQL Query Is a Bad Idea,作者:Javin Paul

【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】

【编辑推荐】

  1. 抛开复杂的架构设计,MySQL优化思想基本都在这了
  2. MySQL知识体系——索引
  3. 2019年4月数据库流行度排行:Oracle持续增长股价获新高
  4. 1000行MySQL学习笔记,不怕你不会,就怕你不学!
  5. AWS云迁移实践:从Oracle到AWS Aurora之旅
【责任编辑:庞桂玉 TEL:(010)68476606】

点赞 0
分享:
大家都在看
猜你喜欢

订阅专栏+白菜送彩金大全

CentOS文件服务的最佳实战

CentOS文件服务的最佳实战

涨薪跳槽必备技能
共15章 | 追风蚂蚁

79人订阅学习

小白网工宝典

小白网工宝典

一次搞定思科华为
共15章 | 思科小牛

286人订阅学习

防火墙大佬修炼手册

防火墙大佬修炼手册

网工达人必备
共20章 | 捷哥CCIE

322人订阅学习

读 书 +白菜送彩金大全

征服Python—语言基础与典型应用

Python是目前流行的脚本语言之一。本书由浅入深、循序渐进地讲解如何使用Python进行程序开发。全书内容包括Python安装、开发工具简介、Pyth...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊

51CTO服务号

51CTO播客

博聚网