SQL实战经验 - 避免使用SELECT *的9个理由及2个例外情况
· 阅读需 9 分钟
Copyright © 2023 PawSQL
我们经常会看到一些文章警 告使用
SELECT *
是一种错误的习惯,应该明确地指定查询的列名,譬如在最新《阿里java开发手册(泰山版)》中对此是作为强制性的规则。不过,大家对其原因只是一知半解。本文将从两个角度解释避免使用SELECT *
的9个理由,同时讨论两个合理使用SELECT *
的例外场景。
性能问题
从性能的角度,在应用中使用SELECT *
可能会引起查询的性能问题,主要表现在以下六个方面,
- 增加解析成本:用
SELECT *
数据库需要解析更多的对象、权限、属性等相关内容,这个影响可能较小,但是它确实会对数据库的元数据查询造成一定的压力。 - 增加IO操作,对于无用的大字段,如 varchar、blob、text,会增加 IO操作;数据库一般会把超过一定长度的大字段,存放在单独的表空间中,因此对这些字段的访问会额外地增加一次IO操作。
- 增加网络消耗,带上如LOB/TEXT之类的无用的大文本字段,传输数据量会成多倍地增涨,特别是如果数据库和应用程序不在同一台机器,这种开销非常明显。
- 增加内存消耗,不管您是否使用这些列,您的应用程序都需要把它们接收到内存,这可能会无谓的消耗大量的内存,影响程序的性能及健壮性,甚至造成内存溢出,应用崩溃。
- 影响索引选择,对于使用
SELECT *
的查询语句,优化器会放弃覆盖索引策略优化的可能性,导致需要回表或是全表扫描。 - 影响索引推荐,PawSQL的索引推荐引擎能够分析SQL的结构,对符合条件的表上创建索引(三种情况:定位数据、避免排序、避免回表)以提升查询性能,具体请参考《创建高效索引的准则》。对于使用
SELECT *
的查询语句,PawSQL索引推荐引擎将不考虑进行覆盖索引的推荐。
维护代价
从代码维护的角度,在应用中使用SELECT *
可能会导致维护变得困难,主要表现在以下三个方面,
- 代码可读性:使用SELECT * 会降低查询的可读性,这是因为使用SELECT * 会使查询语句不容易理解,开发人员需要查看表定义来确定到底查询的是什么数据,同时也难以进行调试。
- 列名对齐:
- 在通过Mybatis框架开发应用时,增加或是删减字段,容易与 resultMap 配置不一致;
- 当使用
SELECT *
定义视图时,增加或是删减字段,都可能导致视图失效, - 您可能会经常使用
SELECT * into INSERT . . .
之类的语句,以实现将某些数据从一张表复制到另一张表。如果在两张表中,各个列的排列顺序略有不同,那么就可能会出现将不正确的数据复制到错误列中的情况。
- 列名冲突:如果您在连接查询中使用了
SELECT *
,一旦在多个表中出现了具有相同名称的列,就会导致列名冲突;从而导致数据的消费方使用错误。