Bueno, después de algún tiempo de escuchar comentarios como “MySQL no te sirve para un sitio pequeño, PostgreSQL es mucho mejor”, o “MongoDB no es bueno”, me decidí por probar por mi mismo la velocidad de cada uno de estos motores.

Preparando la DB

Empecé colocando en cada uno, una base de datos real de tuits, que he estado recolectando desde hace unos dos años con un bot (@cuxibamba; utiliza MySQL, y, de momento, tiene 69255 tuits y 12313 usuarios)

Para colocar la base de datos de @cuxibamba en MongoDB, utilicé MongoHub, que tiene una utilidad nativa para importar de MySQL.

Tuve un poco de problemas colocando la data dentro de PostgreSQL, pero al final lo logré con taps (muy recomendado, por cierto).

Capturas de cómo inician las DB:

PostgreSQL

PostgreSQL

MySQL

MySQL

MongoDB

MongoDB

Primer test

Contando los tuits 10000 (diez mil) veces (count(*))

PostgreSQL count

PostgreSQL count

MySQL count

MySQL count

MongoDB count

MongoDB count

Resultados:

  • PostgreSQL: 164.97 segundos
  • MySQL: 151.67 segundos
  • MongoDB: 4.69 segundos (35 veces menos que PostgreSQL)

Pd. Sí, yo también me sorprendí, y revisé dos veces el script, por si me había equivocado en algo.

Segundo test

Consultando una palabra aleatoria (generada por ruby) 500 veces (where text like '%word%'). Dos partes:

  1. contar cuántas veces aparece dentro del contenido de los tuits
  2. hacer la proyección de los resultados; no solamente el conteo
PostgreSQL query random word

PostgreSQL query random word

MySQL query random word

MySQL query random word

MongoDB query random word

MongoDB query random word

Resultados:

  • PostgreSQL: 20.71 segundos al contar cuántos resultados (count()), 20.77 segundos al hacer la proyección de los resultados y asignar a una variable cada uno.
  • MySQL: 26.4 segundos al contar cuántos resultados (count()); 69.91 segundos al hacer la proyección y asignar los resultados a variables.
  • MongoDB: 63.7 segundos al contar los resultados (count()); 65.08 segundos al hacer la proyección y asignar los resultados.

Conclusiones de este test:

  1. PostgreSQL se toma el mismo tiempo en hacer un conteo de los datos que coinciden con los criterios, que cuando selecciona los datos. Logró un muy buen tiempo en este test.
  2. MySQL se toma mucho menos tiempo cuando cuenta cuántas tuplas coinciden con el criterio, que cuando selecciona cada tupla para utilizarla luego
  3. MongoDB se tomó mucho más tiempo en este test. Probablemente esto sea culpa mía; no pude encontrar un equivalente a: select * from tweets where text like '%word%'; en mongo; en su lugar, estoy utilizando una expresión regular, la cual, obviamente va a coincidir con más resultados y va a costar más recursos.

Tercer test

Select buscando por id (primary key) 1000000 (un millón) veces (los ids son generados aleatoriamente por ruby entre 1 y 69255).

PostgreSQL find by id

PostgreSQL find by id

MySQL find by id

MySQL find by id

MongoDB find by id

MongoDB find by id

Resultados:

  • PostgreSQL: 763.98 segundos
  • MySQL: 652.39 segundos
  • MongoDB: 552.51 segundos

Cuarto test

En mi opinión, el más importante: el CRUD, compuesto por lo siguiente:

  1. Crear 10000 (diez mil) tuits.
  2. Encontrarlos (por su id único) y actualizar su texto (guardándolo en DB nuevamente).
  3. Encontrar nuevamente los 10000 tuits y actualizar tres veces el contenido de cada uno, guardando en DB cada vez que se actualice. (Es decir, tres veces por tuit)
  4. Encontrar cada uno de los 10000 tuits (por su id) y eliminarlo 
PostgreSQL CRUD

PostgreSQL CRUD

MySQL CRUD

MySQL CRUD

MongoDB CRUD

MongoDB CRUD

Resultados:

  • PostgreSQL:
    • 38.82 segundos para almacenar diez mil tuits
    • 35.45 segundos para encontrar y actualizar diez mil tuits
    • 106.39 segundos para encontrar los tuits y actualizar tres veces cada uno
    • 23.54 segundos para eliminar los tuits
    • Total: 204.2 segundos
  • MySQL:
    • 40.18 segundos para almacenar diez mil tuits
    • 29.71 segundos para encontrar y actualizar diez mil tuits
    • 87.32 segundos para encontrar los tuits y actualizar tres veces cada uno
    • 22.55 segundos para eliminar los diez mil tuits
    • Total: 179.76 segundos
  • MongoDB:
    • 4.81 segundos para almacenar diez mil tuits
    • 18.13 segundos para encontrar y actualizar diez mil tuits
    • 54.86 segundos para encontrar los tuits y actualizar tres veces cada uno
    • 14.9 segundos para eliminar diez mil tuits
    • Total: 92.7 segundos (casi la mitad de MySQL, menos de la mitad de PostgreSQL)

Conclusiones: (?)

  • MongoDB rocks, NoSQL rocks (sí, soy fanboy)
  • MongoDB podría llegar a ser el doble de rápido comparado con MySQL y PostgreSQL (?)
  • En el segundo test, como detallé, MongoDB se queda atrás por bastante porque no he podido encontrar (todavía) una manera de hacer where field like %text% (probablemente debe haberla); y tuve que utilizar una expresión regular que disparó el consumo de recursos
  • MySQL es más rápido que PostgreSQL, excepto cuando tiene que hacer una proyección con una (o varias) condiciones (where). Será que PostgreSQL indexa mejor los datos? (ver segundo test)
  • A PostgreSQL le costó bastante actualizar la información de cada tuit (último test)

Espero que les sirva de algo. El hardware de mi Mac es:

  • Procesador: 2.3 Ghz Intel Core i7
  • Memoria: 8GB 1600Mhz DDR3
  • HD: APPLE SSD SM256E Media ( ~500MB/s )