ActiveRecord vacío? vs contar

Durante una discusi√≥n con un compa√Īero de trabajo sobre la optimizaci√≥n de consultas sobre rieles, ¬Ņnecesito demostrar mi teor√≠a de que el recuento es m√°s r√°pido que el vac√≠o? porque en el primer m√©todo, el registro activo se realiza directamente sobre sql y en el segundo est√° verificando la longitud de la matriz dada por el resultado.

Mi entorno

ruby 1.9.3-p448
rails
3.2.6

Entonces, para demostrarlo, hice el siguiente punto de referencia

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

aquí la esencia

Consola

Y mi sorpresa fue que ambas consultas usan COUNT (*)

contar

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

¬Ņvac√≠o?

[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 referencia

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

Conclusión

¬ŅVac√≠o? El m√©todo es un poco m√°s r√°pido que contar, as√≠ que no temas usarlo, especialmente si lo llamas varias veces. Mi preocupaci√≥n y espero que alguien pueda responder por qu√© es m√°s r√°pido y por qu√© est√° llamando a COUNT (*) porque me parece que ActiveRecord est√° haciendo toda la magia.

Actualización 29/07/2013

Para confirmar mis dudas, ejecuto las mismas pruebas en la base de datos del escenario y con una muestra grande 1000 veces. ¬ŅY adem√°s de las leves diferencias vac√≠as? sigue superando la cuenta en tiempo real.

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