1、在PostgreSQL中这三种count是有区别的:
select * from
中的*
将扩展表的所有列,因此,许多人认为使用count(*)
效率低下,应该写count(id)
或count(1)
代替。
count(*)
中的*
与select *
中的*
是完全不同的:
1)count(*)
中的*
仅仅代表row并不会展开它,写入count(1)
与count(*)
是相同的效果,count(1)多了一步计算,在CPU很好的情况下,差别不大。
2)count(id)
有些不同,它只计算id是NOT NULL的行数。因此避免count(*)
没有任何用处,反而count(*)
的速度还会更快。
2、那么,有人会问,count(*)走索引会不会更快?
扫描一个小的索引比全表扫描代价要小很多,特别是列数非常多的情况下,IO的压力也小很多。但是,由于PostgreSQL的MVCC实现方式,每行的可见性在不同的事务中是不一样的,每个事务需要执行具体的扫描过程才能确定该行在本事务中是否可见!
为了缓解这个问题,PostgreSQL引入了visibility map,专门存储表块中所有原则是否对所有人可见。如果是,那么就不必判断每行的可见性,只有部分刚刚写入、更新的块,不是对所有事物可见的,那么这部分块才需要进行遍历块中每行的可见性。
所以,如果大多数表块都是可见的,那么索引扫描就不需要再访问具体的元组来确定可见性了,直接扫描索引可以确定,这样扫描是更快的。
另外,vacuum会更新visibility map,所以,如果想要使用索引来加速count(*),则需要保证autovacuum的频率足够。
下面来做个试验:
--后续:创建主键索引,并不走···,可能数据量不够(100万)