HOT:Inserciones Masivas en MongoDB vs Sql Server (II)

DESCARGO DE RESPONSABILIDAD

Antes de empezar la entrada me gustaría dejar claro que esto es un pasatiempos, una forma de dilucidar quien pagaba las cenas durante el tiempo que nos toco a los dos estar perdidos en una ciudad que no es la nuestra con nuestros respectivos trabajos. La idea de esta serie de blogs no es ver si queremos más a Papa o a Mama, a Sql Server o a una NoSQL. Los resultados que se obtengan no tienen porque hacer pensar que una es mejor que la otra ( sobre todo cuando son compatibles) y por supuesto el performance no es una(la única) razón de selección de una NoSQL como Mongo, escalabilidad, schema-free, base, last-update ni de un sistema transacciónl como Sql Serve. Si esto te queda claro y quieres jugar con nosotros, y por supuesto, aprender como lo hemos hecho nosotros, a forzar situaciones como la presente tanto de Sql Server como de Mongo entonces sigue leyendo…

Bueno, seguro que muchos habéis leido la entrarada de mi compañero de batallas y amigo Pablo Doval sobre un pequeño pique “paga cenas” a ver quien insertaba de una forma más rápida 500 K de registros. En la primera entrada de mi contrincante hemos podido ver como su primer esfuerzo ha resultado en 4 segundos escasos, quiero imaginarme que con escasos no se refiere a 0,9 por lo que entenderé que mi primer reto es superar simplemente 4 segundos. Bien, 4 segundos, no está nada mal, sobre todo porque teniendo en cuenta lo que ha utilizado me temo que tiene un gran arco de mejora ( aunque no seré yo quien se lo diga, más que nada porque de Sql Server el ya sabe mejor que yo …). Vamos a ver que podemos hacer con nuestro jueguete, por supuesto, no empezaremos haciendo ninguna optimización, lo más simple, así tendremos una ligera idea de por dónde andamos.

 

El primer intento

 

Tal y como acabo de comentar el primer intento será lo mas simple posible, insertaremos en MongoDB 500K documentos. Si, documentos, para los que no lo sepais, MongoDb es una base de datos documental, entendiendo como esto a algo similar a lo que podéis ver en la imagen de la derecha. Las normas de nuestra pequeña apuestas decían que teníamos que inUntitledsertar 500K documentos ( el filas ) con un tipo de datos Guid y una cadena con 20 caracteres. Por lo tanto, abriremos un proyecto de Visual Studio 2010 y vamos a empezar a jugar. Lo primero será agregar las librerías necesarias para trabajar con Mongo DB, para ello podemis ir hacia la sección de drivers de Mongo DB y descargar los de C# o mejor aún utilizar el paquete de NuGet que esta gente tiene disponible, concretamente el paquete se llama mongocsharpdriver.

 

Levantando el servidor

 

Lógicamente, antes de conectarnos tenemos que levantar un servidor de MongoDB, para ello, por ahora, no utilizaremos ninguna setting especial, de hecho, lo levantaremos como una consola y no como un servicio de Windows ( si, ya se que eso puede tener un impacto, veremos si es cierto… ). Es decir, levantaremos el servidor con las simples instrucciones siguientes:

 

mongod.exe –dbpath c:\mongo\data [c:\mongo\data es el path para alojar la base de datos]

Ahora, es hora del código, con las siguientes lineas voy a acceder a una colección llamada tests en una base de datos llamada apuesta dónde posteriormente intentaré introducir los 500 K registros.

 

        static MongoCollection GetCollection()
        {
            var server = MongoServer.Create("mongodb://localhost");
            var database = server.GetDatabase("apuesta");

            return database.GetCollection("tests");
        }

Ahora, solamente me queda darle a mi bucle y esperar los resultados para ver desde dónde vamos a empezar a jugar, espero sinceramente que no sea muy alto porque 4 segundos es un muy buen número. Mientras me preparaba para hacerlo me puse a pensar si lo haríamos de forma tipada o no. Es decir, el API de MongoDB me permite definir los distintos documentos mediante clases que posteriormente el serializará al formato de trabajo. Aunque no quería hacer ninguna optimización temprana me parecía que esto sería un poco estúpido y por lo tanto trabajaría directamente con documentos no tipados, es decir, con BsonDocuments.

 

        static void Main(string[] args)
        {
            var collection = GetCollection();

            var watch = Stopwatch.StartNew();

            for (int i = 0; i < 500000; i++)
            {
                collection.Insert(new BsonDocument()
                {
                    {"Guid",Guid.NewGuid()},
                    {"Data","XXXXXXXXXXXXXXXXXXX"}
                });
            }

            watch.Stop();
            Console.WriteLine(watch.Elapsed);
            Console.ReadLine();
            
        }

……………………. ( redoble de tambores)… 18,74 segundazos…… bufff, más de 4 veces que el mejor número de Pablo. Lo primero que hago es comprobar que no he comentido un error, que todos los datos estan en la base de datos, por lo que me conecto a mongo y hago una revisión del numero de documentos y del formato que contienen, en la siguiente imagen podéis ver los pasos que he seguido desde la shell de MongoDb para hacerlo.

 

Untitled2

 

 

….. unos ínfimos cambios y otro disparo….

 

Bien, estamos lejos, pero la verdad, teniendo en cuenta como lo hicimos, tampoco es que me asustará demasiado, hay dos cosas que podemos arreglar rápidamente, la primera es que cuando levantamos el servidor de Mongo como consola no desabilitamos el stdout ni el nivel de verbosidad, por lo tanto, segurmanente eso esté influyendo bastante.  La segunda es que mongo dispone de un sistema de batching por el cual podemos insertar un conjunto de documentos de forma simultanea.

 

Empezaremos los cambios por levantar una instancia del servidor de mongo como un servicio de windows con la siguiente parametrización:

 

mongod –-install [lo instalamos como un servicio]

       --diaglog 0 [deshabilitamos los diagnostics log]

       --quiet [reducimos la verbosidad de standard out

       --nojournal [ eliminamos la feature introducida en 1.8 para asegurar recuperación de datos no insertados en caso de crash]

Ahora, le toca la parte al código,  vamos a hacer el batching, para ello, modificamos nuestro código de inserción por el siguiente:

 

        static void Batching()
        {
            var collection = GetCollection();

            int max = 500000;
            int batch = 1000;
            int iterations = max / batch;

            int count = 0;
            var watch = Stopwatch.StartNew();
            for (int i = 0; i < iterations; i++)
            {
                var data = new BsonDocument[batch];
                while (count < batch)
                {
                    
                    data[count] = new BsonDocument()
                    {
                        {"g",Guid.NewGuid()},
                        {"d","XXXXXXXXXXXXXXXXXXX"}
                    };

                    ++count;
                }

                collection.InsertBatch(data);
                count = 0;
            }

            watch.Stop();
            Console.WriteLine(watch.Elapsed);
            Console.ReadLine();

        }

Ahora tomamos el tiempo y es ….5.005 segundos…. nada mal, si señor, estamos cerca ya de nuestro amigo…. pero aún falta ganar un segundo por algun lado. La primera parece pensar en jugar con los tamaños del batch pero después de algunas pruebas la mejora no es substancial como para ponerla, en mi máquina mi mejor respuesta es con un tamaño de 600  y a partir de 1500 los tiempos se hacen muy grandes. Por lo que parece que se mueve mejor con batch pequeños de estos documentos que muy grandes…

 

 

…tercer disparo y Pablo paga la cena (hoy)

 

Hay que ganar un segundo, ese es el reto ahora. Como lo hacemos?? bueno, a ver, vamos a revisar las opciones de inserción para ver si podemos tunear algun parámetro. Si, nos fijamos en las sobrecargas de InsertBatch, veremos que podemos incluir unas opciones de insercion por medio de la clase MongoInsertOptions. Si revisais esta clase, veréis  que hay tres parámetros importantes, CheckElementNames,SafeMode y Flags. El primero, nos permite decidir si queremos comprobar los nombres de los documentos, claves, collecciones etc antes de procesar un insert, el segundo permite especificarnos el modo de seguridad por defecto y el tercero el comportamiento en caso de fallo. Vamos a tunear estas opciones con nuestros batch y a ver que resultado tenemos….

 

            var insertOptions = new MongoInsertOptions(collection);
            insertOptions.CheckElementNames = false;
            insertOptions.SafeMode = SafeMode.False;
            insertOptions.Flags = InsertFlags.ContinueOnError;

…youhuuuuu 3.50 segundos… Pabloooooooooooooooooooooooooooooooo pagas la cena!!!!!!!!!!!!!!!!!

 

 

…aún así, sigo preocupado

 

Si, sigo preocupado porque Pablo tiene buenas posibilidades de mejora y yo, viendo las estadisticas de mi Mongo, siguiente imagen, veo que si quiero bajar de esos tiempos tengo que cambiar algún concepto y usar algo más de artillería… pero no se si me llegará…. en fin, ya veremos si supera los 3.50 y por cuanto lo supera…

 

Untitled3

 

Nos veremos en la siguiente…

Unai

Published 18/11/2011 11:36 por Unai
Comparte este post:
http://geeks.ms/blogs/unai/archive/2011/11/18/hot-inserciones-masivas-en-mongodb-vs-sql-server-ii.aspx

Comentarios

# re: HOT:Inserciones Masivas en MongoDB vs Sql Server (II)

No sabía si dejar el comentario en este post o en el otro, pero como de momento aquí hay menos, lo dejo aquí.

¿Las pruebas las estáis haciendo sobre la misma máquina?

Friday, November 18, 2011 11:55 AM por Juanma

# re: HOT:Inserciones Masivas en MongoDB vs Sql Server (II)

Buena pregunta Juanmma, la respuesta es un poco gallega pero SI/No, es decir, los dos tenemos portatil de empresa con las mismas características ( aunque distinto  modelo )por lo que los numeros podrían variar algo por el tema de instalaciones o similares. No obstante, hemos corrido mis pruebas en su maquina sin diferencias apreciables, por lo que entendemos que las mejoras que nos iremos haciendo uno sobre el otro son reales, asumiendo que puede existir un porcentaje de variación.

No obstate, en "la revision final" pondremos una tabla comparativa de las distintas opciones, pasadas mejoras, etc usando el mismo entorno, y lo haremos en dos máquinas por si puedieramos extrar alguna información de distorsión...

unai

Friday, November 18, 2011 12:16 PM por Unai

# re: HOT:Inserciones Masivas en MongoDB vs Sql Server (II)

Pero en tu ejemplo no has probado a utilizar paralelización, si lo haces, seguro que podras mejorar, una pregunta, MongoDB dispone de un sistema de transacciones y bloqueos ???

Un saludo.

Friday, November 18, 2011 12:50 PM por Juan Irigoyen

# re: HOT:Inserciones Masivas en MongoDB vs Sql Server (II)

Juan tio, déjame algo para más adelante... que igual lo necesito :-). Con respecto a las transacciones o bloqueos Mongo es Last Updated, hay bloqueos a nivel de colección, en la imagen ultima puedes ver que estoy teniendo con esa orientación un 92% de bloqueos, por eso estaba "preocupado"...

Friday, November 18, 2011 12:59 PM por Unai

# re: HOT:Inserciones Masivas en MongoDB vs Sql Server (II)

jajaja, que conste que yo soy de los que quiere que muerdas el polvo… y que invites a Pablo con un par de buenas botellas de La Tache...

Saturday, November 19, 2011 12:37 AM por Juan Irigoyen

# re: HOT:Inserciones Masivas en MongoDB vs Sql Server (II)

Pero juan, que mal me quieres hombre...porque esas ganas de que yo muerda el polvo!!!!!!!! O es por el Sql Server!! Acuérdate del disclaimer, esto no es más que un juego, no extraigas ninguna conclusión mas alla del aprendizaje, que será bastante...

Unai

Saturday, November 19, 2011 11:29 AM por Unai

# re: HOT:Inserciones Masivas en MongoDB vs Sql Server (II)

Un juego, un juego...., esto es la *** guerra, esta en entredicho el prestigio de Pablo y encima con concesiones antes de empezar, dejando de lado las bulk insert, no se, esto me huele a tongo...

Saturday, November 19, 2011 7:30 PM por Juan Irigoyen

# re: HOT:Inserciones Masivas en MongoDB vs Sql Server (II)

Lo que a mi me ha sorprendido ha sido la falta de necesidad de conocer el motor de mongoDB como si lo hubieras parido para conseguir optimizaciones.

En mi empresa tenemos una lista de cosas a comprobar con respecto al rendimineto de SQL Server; es una enorme ristra de cosas y algunas son tan hermeticas y oscurantistas que me dan hasta yuyu pensar en ellas... :S

Monday, November 21, 2011 12:08 PM por Crowley

# Roar: Inserciones Masivas en MongoDB vs SQL Server (IV)

Me alegra comprobar que, al parecer, el pequeño reto que nos traemos Unai y yo está provocando cierto

Tuesday, November 22, 2011 8:23 PM por Surviving the Night

# [Windows Phone 7.5] Inserciones masivas en SQL Server CE vs SQL Server vs MongoDb

Hola a todos! Desde hace unas semanas, mis compañeros Pablo Doval y Unai Zorrilla están

Thursday, December 8, 2011 1:16 PM por Josue Yeray