ActiveRecord vazio? vs contagem

Durante uma discussão com um colega de trabalho sobre a otimização de consultas sobre trilhos, preciso provar minha teoria de que contar é mais rápido do que vazio. pois no primeiro método active record ele está fazendo diretamente sobre sql e no segundo está verificando o comprimento do array dado pelo resultado.

Meu ambiente

ruby 1.9.3-p448
rails
3.2.6

Então, para provar isso, fiz a próxima referência

Código

Benchmark.bm do |bm|

bm
.report("count") do
10.times{ User.where('id>0').count<0 }
end

bm
.report("empty?") do
10.times{ User.where('id>0').empty? }
end

end

aqui a essência

Console

E minha surpresa foi que ambas as consultas usam COUNT (*)

contagem

[DEBUG]    (0.6ms)  SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id > 0)
[DEBUG] (0.6ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id > 0)
[DEBUG] (0.4ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id > 0)
[DEBUG] (0.5ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id > 0)
[DEBUG] (0.5ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id > 0)
[DEBUG] (0.4ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id > 0)
[DEBUG] (0.4ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id > 0)
[DEBUG] (0.4ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id > 0)
[DEBUG] (0.4ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id > 0)
[DEBUG] (0.4ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id > 0)

vazio?

[DEBUG]    (0.4ms)  SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id>0)
[DEBUG] (0.5ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id>0)
[DEBUG] (0.4ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id>0)
[DEBUG] (0.3ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id>0)
[DEBUG] (0.4ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id>0)
[DEBUG] (0.3ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id>0)
[DEBUG] (0.4ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id>0)
[DEBUG] (0.3ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id>0)
[DEBUG] (0.3ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id>0)
[DEBUG] (0.4ms) SELECT COUNT(*) FROM "users" WHERE "users"."deleted_at" IS NULL AND (id>0)

Resultado de referência

          user     system      total      real
count
0.020000 0.000000 0.020000 ( 0.023109)
empty
? 0.020000 0.000000 0.020000 ( 0.018685)

Conclusão

Vazio? método é um pouco mais rápido do que contar, então não tenha medo de usá-lo, especialmente se você chamá-lo várias vezes. Minha preocupação e espero que alguém possa responder porque é mais rápido e porque está ligando para COUNT (*) porque me parece que o ActiveRecord está fazendo toda a mágica.

Atualização 29/07/2013

A fim de confirmar minhas dúvidas, eu executo os mesmos testes no banco de dados do stage e com uma grande amostra por 1000 vezes. E além das pequenas diferenças vazias? ainda batendo contar em tempo real.

          user     system      total      real
count
2.370000 0.100000 2.470000 ( 24.989100)
empty
? 2.470000 0.090000 2.560000 ( 24.867949)