解决方法
sql是声明性的,您可以指定所需的内容.这与指定如何获得所需内容不同.这意味着数据库引擎可以以其认为最有效的方式自由地实现您的查询.许多数据库优化器会将您的查询重写为成本较低的替代方案(如果此类计划可用).
鉴于下表:
table( pk not null,color not null,nullable null,unique(pk),index(color) );
…以下所有内容在功能上是等效的(由于count和nulls的机制):
1) select count(*) from table; 2) select count(1) from table; 3) select count(pk) from table; 4) select count(color) from table;
无论您使用哪种形式,优化器都可以自由地将查询重写为另一种形式(如果它更有效). (同样,并非所有优化器都足够复杂以实现此目的).唯一索引(pk)将比整个表更小(占用的字节数).因此,计算索引条目的数量而不是扫描整个表格会更有效.在Oracle中,我们有位图索引,它也压缩重复的字符串.如果我们在颜色列上使用了这样的索引,它可能是最小的扫描索引. Oracle还支持表压缩,在某些情况下,表压缩会使物理表小于复合索引.
1. TL; DR;
您的特定dbms将拥有自己的一组工具,可以启用不同的重写规则以及执行计划.这使得这个问题有些无用(除非我们讨论特定dbms的特定版本).我建议在所有情况下使用COUNT(*)因为它需要最少的认知努力来掌握.
2.在选择a,b,c与选择*
在您编写并投入生产的代码中,SELECT *的有效用途非常少.想象一下包含Bluray电影的表格(是的,电影在此表中存储为blob).所以你把你的awesomesauce抽象层拼凑在一起,把SELECT * FROM电影放在id =?在getMovies(movie_id)方法中.我将不再解释为什么SELECT name FROM movies将通过网络传输速度稍快一些.当然,在大多数现实情况下,它不会产生明显的影响.
性能的最后一点是,当查询中所有引用的列(选中,已过滤)作为索引(称为覆盖索引)存在时,数据库根本不需要触及该表.只能通过扫描索引完全解决.通过选择所有列,您可以从优化程序中删除此选项.
关于SELECT *的另一件事情比任何事情都严重得多,它会在表格的特定物理布局上创建隐式依赖关系.让我解释.请考虑以下表格:
table T1(name,id) table T2(name,id)
以下声明……
insert into t1 select * from t2;
……如果发生以下任何一种情况,将会破坏或产生不同的结果:
>重新排列任何表列,例如T1(id,name)
> T1获得一个额外的非空列
> T2获得另一列
2. TL; DR;如果可能,请明确指定所需的列(最终,您必须这样做).此外,选择较少的列比选择更多列更快.对显式选择的可能副作用是它为优化器提供了更大的自由度.