Comparando MongoDB y Mysql

2021-04-03 - Categorías: PHP

Estoy como niño con juguete nuevo con MongoDB, esta base de datos no relacional que está tan de moda en los últimos tiempos. Había escuchado que con las BD no relacionales no hacía falta definir una estructura, que funcionan muy rápido, que en los grandes proyectos con ingentes cantidades de datos son la mejor opción..

Así que aquí estoy haciendo un howto o codekata con el último driver de PHP para MongoDB. Hay librerías de más alto nivel como la propia mongodb/mongodb para Composer, o el conocido Doctrine con su ODM, pero para este post he tratado de programarlo a pelo para sacar el máximo rendimiento.

Un poco de teoría sobre las BDs no relacionales orientadas a documentos

Parafraseando un poco las teorías de las BDs no relacionales, en concreto sobre las orientadas a documentos.. aquí las tablas son colecciones, que tienen dentro en cada fila un documento, y además dentro de un documento puede haber incluidos otros documentos. Es importante ser consciente de que con bases de datos no relacionales no tenemos tablas definidas, ni campos definidos de forma inmutable, no hay relaciones, no hay integridad referencial, los campos definidos pueden variar de un documento a otro.. entre otras cosas, es bien diferente a trabajar con BDs relacionales.

El motor de la BD no necesita mucho tiempo para hacer su trabajo, con lo que funcionan muy rápido. Los proyectos con BD no relacionales se pueden arrancar más rápido ya que no hay que definir la estructura de la BD, y es luego muy flexible. Por contrapartida, para estas BDs no relacionales no es tan fácil hacer consultas con fórmulas matemáticas, entrelazar los datos para sacar informes, o mantener fácilmente los datos bien estructurados ya que estas bases de datos te dan mucha flexibilidad.

Instalando MongoDB en GNU/Linux

En los sistemas operativos GNU/Linux con APT bastaría con hacer:

sudo apt install mongodb-server

..y tendremos en poco tiempo instalado en el puerto 27017 local y sin contraseña MongoDB. Para las demás versiones me remito a la página oficial desde donde se pueden instalar para Mac, Windows o los diferentes instaladores de distribuciones de Linux:
https://www.mongodb.com/try/download

MongoDB Compass, un buen SGBD

Hay varios clientes para esta BD, pero en la misma página oficial de MongoDB han publicado como gratis al buen Compass:

Con este Sistema Gestor de Base de Datos podemos hacer todo tipo de consultas sobre la BD o ver los resultados de lo que estemos programando, muy recomendable 😉

Creando en PHP una primera colección en MongoDB

Es bien sencillo de usar si no usamos ninguna librería. Simplemente damos de alta un manejador de MongoDB y luego le pasamos tantas consultas como queramos. Se configuran de forma parecida a como se puede hacer en Compass. Por ejemplo, para dar de alta el manejador:

$mongoManager = new \MongoDB\Driver\Manager('mongodb://127.0.0.1:27017');

Ahora para insertar valores en una colección, simplemente tenemos que mandarlos a insertar en la colección que queramos. No hay que atender a estructuras, ni si la tabla/colección existe, etc.. simplemente con 3 líneas ya estaría:

$bulkWrite = new \MongoDB\Driver\BulkWrite();
$bulkWrite->insert($insertData);
$mongoManager->executeBulkWrite('testing.acollection', $bulkWrite);

En $insertData tendremos un array de datos, da igual cuántos campos y subcampos si dentro tiene otros documentos, MongoDB almacenará el documento en la colección que le digamos. En el código fuente anterior se inserta el documento en la BD testing, en la colección llamada acollection.

Ahora todo junto, para probar creando una colección con 1 millón de datos, se podría hacer con algo parecido a esto:

<?php

$mongoManager = new \MongoDB\Driver\Manager('mongodb://127.0.0.1:27017');
//$mongoQuery = new \MongoDB\Driver\Query([]);

$startTime = microtime(true);
for ($i = 0; $i < 1000000; ++$i) {
    $insertArray = [
        'col1' => md5(uniqid(null, true)),
        'col2' => 'Data '.$i,
        'col3' => 'Data '.$i,
        'col4' => 'Data '.$i,
        'col5' => 'Data '.$i,
        'col6' => 'Data '.$i,
        'col7' => 'Data '.$i,
        'col8' => 'Data '.$i,
        'col9' => 'Data '.$i,
        'col10' => 'Data '.$i,
    ];

    //$insertArray['_id'] = new \MongoDB\BSON\ObjectID();
    $bulkWrite = new \MongoDB\Driver\BulkWrite();
    $bulkWrite->insert($insertArray);

    $mongoManager->executeBulkWrite(
        'testing.acollection',
        $bulkWrite
    );
}
$endTime = microtime(true);
echo 'Taken time: '.($endTime - $startTime).' secs.'.PHP_EOL;

Si esto lo dejamos correr podemos ver que va muy rápido:

Mongo 1M inserts
MongoDB 1M inserts..

¡Apenas me ha tardado 200 segundos en insertar un millón de documentos en la colección! Esto es muy rápido.

Comparando en PHP con Mysql

Por probar, creando una tabla en Mysql y haciendo un millón de inserciones con datos parecidos, me ha quedado un código fuente como el siguiente:

<?php

$connection = mysqli_connect('localhost', 'jnj', 'thepass', 'testing');
if ($connection->connect_error) {
    die('Connection failed: '.$connection->connect_error);
}

// sql to create table
$sql = 'CREATE TABLE IF NOT EXISTS atable (col1 varchar(64), col2 varchar(64), col3 varchar(64),
col4 varchar(64), col5 varchar(64), col6 varchar(64), col7 varchar(64), col8 varchar(64),
col9 varchar(64), col10 varchar(64))';

if (true === mysqli_query($connection, $sql)) {
    echo 'Table created successfully!'.PHP_EOL;
} else {
    echo 'ERROR creating table!'.PHP_EOL;
}

$startTime = microtime(true);
for ($i = 0; $i < 1000000; ++$i) {
    $sql = "INSERT INTO atable (col1, col2, col3, col4, col5, col6, col7, col8, col9, col10) VALUES ("
        ."'".md5(uniqid(null, true))."',"
        ."'Data ".$i."',"
        ."'Data ".$i."',"
        ."'Data ".$i."',"
        ."'Data ".$i."',"
        ."'Data ".$i."',"
        ."'Data ".$i."',"
        ."'Data ".$i."',"
        ."'Data ".$i."',"
        ."'Data ".$i."'"
        .");";

    mysqli_query($connection, $sql);
}
$endTime = microtime(true);
echo 'Taken time: '.($endTime - $startTime).' secs.'.PHP_EOL;

mysqli_close($connection);

Para empezar, simplemente se puede ver que necesita de más líneas de código fuente para hacer lo mismo. Por otro lado, si lo dejamos correr, la diferencia de tiempo consumido para hacer lo mismo es muy significativa:

Mysql 1M inserts
Mysql 1M inserts..

Me ha tardado 3600 segundos, una hora aproximadamente, en hacer algo parecido a lo anterior para MongoDB, pero ahora para Mysql.

Terminando y referencias

Si hacer más ajustes al código fuente, para hacer varios inserts de una tacada, ni más pruebas con otro tipo de operaciones, es muy grande la diferencia en tiempos para crear una tabla/colección con un millón de elementos para Mysql o MongoDB. Es una relación 18:1, con lo que donde en MongoDB ha tardado 1.. ¡en Mysql ha tardado 18 veces más!

Para terminar de juguetear un poco sólo me queda remitirte a la documentación oficial de PHP y MongoDB por si quieres seguir adelante:

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

 

© 2021 JnjSite.com - MIT license

Sitio hecho con WordPress, diseño y programación del tema por Jnj.