Saltar al contenido

Firestore vs MongoDB

Ir a la consola

Cómo está hecho y qué mide de verdad

Esta herramienta ejecuta operaciones reales contra Firestore y MongoDB desde un servidor, mide cuánto tarda cada una y transmite las muestras al navegador mientras la corrida sigue. No simula nada.

La parte interesante no es el resultado. Es cuántas maneras hay de medir mal sin enterarse, y qué se hizo en cada caso para no caer.

Un benchmark honesto empieza diciendo qué no mide

Cada muestra incluye el viaje de red hasta la base. Desde Honduras ese viaje ronda los 50 ms, así que la operación de MongoDB cuesta entre 2 y 6 ms y todo lo demás es distancia. Un número sin sus condiciones no significa nada.

01 · Arquitectura

Un solo tipo sostiene todo

El dominio declara un puerto y nada más. La isla de interfaz conoce ese tipo y ninguna otra cosa: no sabe que existe Firestore, ni MongoDB, ni HTTP. Pasar del adaptador simulado al real de Firestore fue cambiar una línea en el composition root.

Es la prueba que vale la pena mostrar: si agregar un motor obligara a tocar la interfaz, el diseño estaría roto.

El puerto BenchmarkRunnerLa isla de interfaz depende del tipo BenchmarkRunner declarado en el dominio. Los cinco adaptadores implementan ese mismo tipo. El composition root en pages/index.astro decide cuál se inyecta.ui/<benchmark-console>Solo conoce el tipo.Nunca importa unadaptador.domain/type BenchmarkRunner = {readonly run: (config, signal) => AsyncIterable<RunEvent>}adapters/mockfirestoremongosequential · httpdepende decumplencomposition root — pages/index.astro elige cuál se inyecta

El runner secuencial también cumple ese puerto. Por eso la interfaz no distingue una corrida de un motor de una de varios: para ella siempre es un único ejecutor.

02 · Recorrido

Qué pasa al apretar ejecutar

La entrada de red se valida elemento por elemento antes de tocar nada. Después los motores corren uno detrás del otro, y cada muestra vuelve al navegador apenas se mide.

Recorrido de una ejecuciónEl formulario envía la configuración al endpoint, que la valida y la pasa al runner secuencial. Firestore corre sus cinco fases y recién entonces corre MongoDB. Cada muestra vuelve al navegador por SSE mientras la ejecución sigue.NavegadorServidor · función en iad1Formulariomotores, operaciones, cargaPOST/api/benchmarkisEngineId · isOperationIdcreateSequentialRunnercumple el mismo puertoFirestore5 fases, una por operacióny recién entoncesMongoDB5 fases, una por operaciónNunca en paraleloCompartirían CPU y ancho debanda de la misma función, ycada uno inflaría la latenciadel otro. Se mediríacontención, no motores.text/event-streammuestra a muestra,sin esperar el finalreduceRunStatetabla y gráfico se repintan

03 · Método

Qué le pasa a cada muestra

El calentamiento existe porque abrir la conexión y llenar cachés cuesta, y ese costo se paga una sola vez. Si entrara en la medición, el primer valor arrastraría la media y ensuciaría la cola.

Anatomía de una faseLas iteraciones de calentamiento se ejecutan y se descartan. Las operaciones que fallan solo suman al contador de errores y no entran en el arreglo. Las muestras restantes se ordenan y de ahí salen p50, p95 y p99.Calentamientose ejecuta y se tiraabrir conexión,llenar cachésMedición · ordenada de menor a mayor52 ms53 ms53 ms54 ms54 ms55 ms55 ms56 ms56 ms57 ms57 ms58 ms58 ms59 ms60 ms61 ms62 ms64 ms67 ms71 ms78 ms96 ms141 msp50p95p99Interpolación lineal entre rangos, no la muestra observada más cercana.Las operaciones que fallan no entran acá.Suman al contador de errores y nada más, así que las columnas de latencia describen únicamente lo que sí llegó a completarse.

04 · Decisiones

Seis maneras de medir mal

Cada una se recorrió por el camino equivocado primero. Están acá porque el error era silencioso: los números salían, se veían bien, y estaban mal.

  1. 01

    El ganador se decide por p95, no por la media

    La cola es lo que el usuario siente. Una media buena con una cola mala se percibe como una aplicación lenta, y al revés no pasa. Un empate exacto o un motor único no dan ganador.

  2. 02

    El gráfico usa escala logarítmica

    Firestore ronda los 200 ms y MongoDB los 2 ms de trabajo real. En escala lineal el segundo sería una raya invisible pegada al eje.

  3. 03

    El rendimiento sale del reloj de la fase, no de la media

    Invertir la media da un número que se rompe al subir la concurrencia: medido, pasar de 1 a 6 workers bajaba el valor reportado de 6.47 a 3.67 op/s mientras el rendimiento real subía de 5.65 a 19.9. Latencia y rendimiento son preguntas distintas; nunca derivar una de la otra.

  4. 04

    deleteOne siembra iteraciones más calentamiento

    Con solo las iteraciones, el calentamiento consume los primeros documentos y la medición vuelve a borrarlos. Firestore no falla al borrar algo inexistente, así que el contador de errores queda en cero y los números salen limpios y falsos.

  5. 05

    Cada operación tiene su colección, con nombre estable

    Un índice compuesto en Firestore se define por colección: un nombre con marca de tiempo obligaría a crearlo de nuevo en cada corrida. La colección se vacía al entrar y al salir de la fase — al entrar también, porque una corrida cortada a la mitad deja documentos y la siguiente mediría contra basura.

  6. 06

    Los índices se igualan de los dos lados

    Firestore indexa cada campo por su cuenta; MongoDB solo el _id. Por eso el adaptador de MongoDB crea el índice compuesto al sembrar: sin él, la consulta filtrada haría un escaneo completo y la comparación mediría un índice faltante, no un motor.

05 · Resultados

Lo medido, y cómo leerlo

30 iteraciones, documentos de 1024 B, concurrencia 1, ejecutado desde Honduras. Cero errores en las diez fases. p95 en milisegundos, más corto es mejor.

Latencia p95 por motor y operación, en milisegundos
MotorinsertOnefindByIdqueryFilteredupdateOnedeleteOne
Firestorenam5 · multirregión127.899.7154.9120.2113.5
MongoDBAtlas M0 · región única54.352.152.755.856.1

Esto no dice que MongoDB sea 2 o 3 veces más rápido

La prueba está en la propia tabla. Firestore hace consenso entre regiones antes de confirmar una escritura, así que si el motor mandara, la brecha en escrituras tendría que ser mucho mayor que en lecturas.

Y no lo es: va de 1.9 veces en findById a 2.4 veces en insertOne. Un factor parejo en todas las operaciones no puede ser el motor. Es la red.

Desplegado en Vercel la función mide desde iad1, mucho más cerca de ambas bases, y estos números cambian. Por eso la región está fijada en la configuración: si el proveedor ubicara la función lejos, el benchmark dejaría de medir la base para medir la topología.

06 · Glosario

Cada término, una vez

Las mismas definiciones que aparecen en los tooltips de la consola. Una sola redacción para las dos superficies: una métrica explicada dos veces termina significando dos cosas.

Latencialatency
Tiempo entre pedir la operación y recibir su confirmación, medido en el servidor. Incluye el viaje de red hasta la base, no solo el trabajo del motor.
p50 · medianap50
La mitad de las muestras tardó menos que este valor. Describe la ejecución típica, no la peor.
p95p95
El 95 % de las muestras tardó menos que este valor. Es la cola que el usuario percibe como lentitud, y por eso el ganador de cada operación se decide aquí y no por la media.
p99p99
El 1 % más lento. Con pocas muestras es muy inestable: un solo pico lo mueve entero.
Mediamean
Promedio de todas las muestras. Una sola muestra extrema la arrastra hacia arriba, así que puede esconder una cola mala tanto como inventarla.
Máximomax
La muestra más lenta de la fase. Dice hasta dónde llegó el peor caso; como es un único dato, no sirve para comparar motores.
Rendimientothroughput
Operaciones completadas por segundo sobre el tiempo real de la fase. No es la inversa de la media: al subir la concurrencia cada operación tarda más y el rendimiento sube igual.
Erroreserrors
Operaciones que fallaron. No entran en los percentiles, así que las columnas de latencia describen únicamente lo que sí llegó a completarse.
Iteracionesiterations
Muestras medidas por cada motor y cada operación. Cuantas más, más confiable es la cola: con diez muestras el p95 es poco más que una anécdota.
Calentamientowarmup
Operaciones que se ejecutan y se descartan antes de empezar a medir, para que abrir la conexión y llenar cachés no se cuele en los números.
Tamaño del documentodocumentSize
Bytes aproximados del documento de prueba. Cuanto más crece, más pesan la red y la serialización frente al motor.
Concurrenciaconcurrency
Operaciones en vuelo al mismo tiempo. Con 1 se mide latencia pura; al subir, cada operación tarda más pero el trabajo total por segundo crece.
Escala logarítmicalogScale
Cada marca del eje multiplica por diez. En escala lineal, un motor de 2 ms al lado de uno de 200 ms sería una raya invisible.

07 · Límites

Lo que no puede afirmar

  • Una corrida por motor a la vez. Las colecciones tienen nombre estable, así que dos ejecuciones simultáneas se pisarían. Es una herramienta de un operador a la vez.
  • El M0 de Atlas comparte CPU. Su cola es más ruidosa: con diez iteraciones se vio un p95 de 835 ms sobre un p50 de 54 ms. Sacar conclusiones de la cola exige muestras largas.
  • Firestore vive en nam5, que es multirregión. Cada escritura replica entre regiones de EE. UU. antes de confirmarse, así que no es comparable contra un cluster de región única sin decirlo en voz alta.
  • Desplegado, la función mide desde iad1 y no desde Honduras. Los números de esta página cambian, y esa es justamente la idea.
Ejecutar una corrida