sql使用select * 的问题

之前有同事规劝我说,查询的时候不要使用select *了,相同情况下,使用select所有字段会更好。

所以我有点想弄明白这究竟是怎么一回事,大概看看网上的人是怎么说的。

 

1.不需要select全部字段的情况下

这个问题的结论应该是很明显的。

我之前用select查询的时候,都是select *,然后映射成一个对象,然后从对象中取我需要的字段。这样确实是很省事,但是肯定会造成资源的浪费。

试想,我只是要一个username的字段而已,直接select username就可以达到我的目的。但是如果select *,这就意味着要把符合条件的所有内容全部输出出来,万一这个表中的字段很多怎么办…

我明明只是需要一个username字段,结果把二三十个字段全都拿出来,然后在对象中进行获取,那么那些没有用上的字段为什么要拿出来呢?这肯定会对cpu的io、磁盘io、缓冲区等资源造成浪费。如果通过网络获取,就会浪费更多的带宽。

这里有三个我感觉很好的回答:

(1)select *最大的问题是可能会多出一些不用的列

这些列可能正好不在索引的范围之内,或是针对*建索引成本过于高昂,导致查询的成本几何级增高。反而是对于网络传输来说,oltp环境多几列(不包括blob数据类型)影响很小。

(2)影响查询速度原因主要有:

1.会查询出不必要的字段

CPU cost,IO cost,Cost,宽带消耗都会增加。

2.影响数据库自动重写优化SQL

Oracle 解析SQL的同时会重写SQL,类似Java中编译class时的编译器自动优化。如图所示,SQL执行过程中完全无视left join 这一段。如果使用 select * ,就不会有这个优化了。

3.解析字段

数据库需要根据数据字典生成一个语法树,然后根据语法生成执行计划。如果使用select * 数据库需要解析更多的 对象,字段,权限,属性相关,在SQL语句复杂,硬解析较多的情况下,会对数据库造成沉重的负担。(SQL语句软解析时不会有影响)

(3)mysql下的情况:

如果是mysql的话(我只回答自己熟悉的领域),select *杜绝了索引覆盖的可能性,而索引覆盖又是速度极快,效率极高,业界极为推荐的查询方式。

例如,有一个表为t(a,b,c,d,e,f),其中,b列有索引,那么,在磁盘上有两棵b+树,即聚集索引和辅助索引,分别保存(a,b,c,d,e,f)和(b,a),如果查询条件中where条件可以通过b列的索引过滤掉一部分记录,查询就会先走辅助索引,如果用户只需要a列和b列的数据,直接通过辅助索引就可以知道用户查询的数据,如果用户select *,获取了不需要的数据,则首先通过辅助索引过滤数据,然后通过聚集索引获取所有的列,这就多了一次b+树查询,速度必然会慢很多。

由于辅助索引的数据比聚集索引少很多,很多情况下,通过辅助索引进行索引覆盖(通过索引就能获取用户需要的所有列),都不需要读磁盘,而聚集索引很可能数据在外存中(取决于buffer pool的大小和命中率),这种情况下,一个是内存读,一个是磁盘读,速度差异就很显著了,几乎是数量级的差异。

此外,作为有着良好编程习惯的程序员,也不应该获取自己不需要的东西,你现在执行select *,以后表结构修改了,如增加了一列或删除了一列,对你的代码影响也很大,如果只是恰好只获取自己需要的那几列,表结构的修改对你的代码影响就会比较小。

我的理解:

前两个回答还是多少能明白一些,第三个回答理解起来感觉很吃力。感觉可以详细研究下第三个回答,因为涉及到数据库原理和执行过程,感觉会很有收获。

2.需要select全部字段的情况下

既然select *和select所有字段都是拿出所有的字段,那么其区别在哪里?他们的执行过程有什么不同吗?但是有一点可以肯定,这两个方法都实现了同样的效果。既然有不同,那么很有可能是数据库的执行计划有区别。

(1)首先自己试验一下

如果不用索引

大概2000条数据左右,字段数不多,没有使用索引。因为担心缓存的影响,做了第二次,可以看见select所有字段的速度确实好像比select *要快一些。

这次我加上索引,加上条件

这里出现了哟个比较奇怪的状况,select *反而比select所有字段要更快,不知道出了什么事情。

(2)网上的答案

1.无论如何都不要使用select *

答案是:无论如何,都不推荐使用 SELECT * FROM xxx

1.SELECT *,需要数据库先 Query Table Metadata For Columns,一定程度上为数据库增加了负担。
但是实际上,两者效率差别不大。

2.考虑到今后的扩展性。
因为程序里面你需要使用到的列毕竟是确定的, SELECT * 只是减少了一句 SQL String 的长度,并不能减少其他地方的代码。

我的理解:

这个观点翻译自:http://stackoverflow.com/questions/65512/which-is-faster-best-select-or-select-column1-colum2-column3-etc

因为不知道怎么去看mysql的执行计划,所以不知道怎么验证第一点。至于第二点,感觉还是能够理解的。

2.没有太大区别

如果select * 与你想查询的字段完全一致,单单就查询来说,select * 并没有降低查询效率。但是实际使用中这种情况极少。

我的理解:

这里说是没有什么太大的区别,但是我自己的实验基本上都是select所有字段比select *的表现要更好。如果要追求更好的性能(并且不怕麻烦),感觉最好还是写成select所有字段的形式。

3.总结

两种情况。

1.不需要查询全部字段的情况

毫无疑问地select字段,避免造成资源浪费。多写sql,不要偷懒,能比selec *带来更好的性能。就是要写多很多sql,比较麻烦,也和程序员的责任心挂钩。

2.需要查询全部字段的情况

网上基本在效率上认为没什么太大的区别。但是我自己实验的结果还是select全部字段表现比较好。所以我觉得可以尽量采用这种方式。

发表评论

电子邮件地址不会被公开。 必填项已用*标注