Postgres: count (*) vs count (id)

11

Saya melihat dalam dokumentasi perbedaan antara count(*)dan count(pk). Saya telah menggunakan count(pk)(di mana pka SERIAL PRIMARY KEY) tidak tahu tentang keberadaan count(*).

Pertanyaan saya adalah tentang optimalisasi internal Postgres. Apakah cukup pintar untuk mengambil bahwa a SERIAL PRIMARY KEYakan ada di setiap baris dan tidak pernah salah dan hanya menghitung baris atau akankah ia melakukan pemeriksaan predikat berlebihan untuk setiap baris? Saya setuju bahwa ini mungkin terlalu banyak optimasi yang tidak berguna, tetapi saya hanya ingin tahu.

Saya melihat pada output dari EXPLAINdan EXPLAIN VERBOSEuntuk count(*), count(id)dan count(id > 50)untuk melihat apakah EXPLAINdisebutkan memeriksa predikat dalam outputnya. Tidak.

lg
sumber

Jawaban:

15

Saya mendapat hasil yang konsisten dalam tes saya berulang-ulang dengan berbagai versi selama bertahun-tahun terakhir:
count(*)adalah sedikit lebih cepat dari count(pk). Ini juga lebih pendek dan sebagian besar waktu lebih cocok dengan apa yang diuji: keberadaan baris.

Tentang:

Apakah Postgres cukup pintar untuk mengetahui bahwa a SERIAL PRIMARY KEYakan ada di setiap baris dan tidak pernah salah

Satu-satunya hal yang relevan adalah NOT NULLkendala. The PRIMARY KEYadalah NOT NULLotomatis, serialatau never falseyang ortogonal untuk pertanyaan.

Dengan count(col), jika PostgreSQL berusaha menjadi pintar dan memeriksa katalog sistem apakah sebuah kolom NOT NULLdan kembali ke yang setara count(*), Anda masih akan memiliki satu pencarian lagi di tabel sistem daripada dengan count(*).

Adapun EXPLAINoutput, ada adalah petunjuk:

EXPLAIN SELECT count(*) FROM ...

Aggregate  (cost=4963.38..4963.43 rows=1 width=0) ...


EXPLAIN SELECT count(pk) FROM ...

Aggregate  (cost=4963.38..4963.43 rows=1 width=4) ...

Artinya, count(col)yang tidak dikonversi ke count(*), bahkan jika itu didefinisikan NOT NULL.

Erwin Brandstetter
sumber
Apakah ini masih terjadi dengan versi yang baru? Saya pikir itu tidak benar-benar membutuhkan pencarian untuk setiap permintaan - itu bisa di-cache.
Ondra Žižka
1
Btw, dengan NOT NULLkolom, perbedaannya besar jika Anda memiliki banyak baris. Dalam kasus kami dengan jutaan baris, COUNT(*)3 kali lebih cepat. (Postgres 9.4)
Ondra Žižka