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萬)