HOT:Inserciones masivas en Sql Sersver vs Mongo DB ( III)

 
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…

 

La bala de la recamara….

 

Me voy a permitir adelantarme al post de Pablo Doval con sus conclusiones puesto que, este finde esta muy, pero que muy ocupado haciendo que el Sql Server de otro ande más rapido. Como había dicho, me preocupaba mucho el tema de mis bloqueos, puesto que o cambiaba de tercio o no tendría mucho margen de mejora. Pensando y pensando (algún comodín también) me puse a ver que podría hacer y recorde que con las Capped Collections de Mongo DB podría ganar algo, puesto que a la hora de crearlas podría especificar el espacio a ocupar y por lo tanto hacer un pequeño prefetch de la base de datos. En realidad, una colección capped no es más que una colección con un tamaño máximo dado y un número de documentos máximo. La definición exacta de las capped collections la tenéis en la siguiente frase:

 

Capped collections are fixed sized collections that have a very high performance auto-FIFO age-out feature (age out is based on insertion order). They are a bit like the "RRD" concept if you are familiar with thatç

Bueno, “high performance auto-FIFO”…. esto es lo que andaba buscando…. Vamos, además, a unirlo con un poco de paralelismo para ver si nos sorprendemos con los resultados que obtengamos. Para ello, lo primero que haremos será levantar nuestro servidor de mongodb con prácticamente las mismas opciones que en la entrada anterior, he incluido alguna más pero no han tenido demasiado efecto…

 

mongod  -- dbpath c:\mongo\data

        -- nohttpinterface

        -- noauth

        -- nojournal

        -- quiet

        -- verbose

        -- diaglog

        -- logpath log.txt

        -- install

Ahora, modificaremos nuestro código para que se cree la colección a utilizar como una capped collection, fíjese que en esta creación hemos puesto ya tamaños máximos de documentos y espacio. Además también hemos realizado otra optimización al poner SetAutoIndex a false eliminando así la creación del índice  sobre _id por defecto.

 

        static MongoCollection SetupAndPrepareCollection()
        {
            var dbSettings = new MongoServerSettings()
            {
                ConnectionMode = ConnectionMode.Direct,
                SafeMode  = SafeMode.False,
                Server = new MongoServerAddress("localhost")
            };

            //create server and get database
            var server = MongoServer.Create(dbSettings);
            var db = server.GetDatabase("speedUp");

            //set collection options
            var collectionOptionsBuilder = new CollectionOptionsBuilder();
            collectionOptionsBuilder.SetAutoIndexId(false);
            collectionOptionsBuilder.SetCapped(true);
            collectionOptionsBuilder.SetMaxSize(40000000);
            collectionOptionsBuilder.SetMaxDocuments(590000);

            string collectionName = "tests";

            if (db.CollectionExists(collectionName))
                db.DropCollection(collectionName);

            db.CreateCollection(collectionName, collectionOptionsBuilder);
            db.SetProfilingLevel(ProfilingLevel.None);

            return db.GetCollection(collectionName);
        }

El paralelismo es sencillo, basta con usar el magnífico API de TPL y agregar unas cuantas Task como se ve a continuación. Como seguramente muchos os preguntéis, he probado diferente número de hilos, y la verdad es que no he obtenido mejor, lo cual, me hace indicar que el problema no es de contención en el procesador, ni de uso, es ya un tema en MongoDB.

 

            var watch = Stopwatch.StartNew();

            var task = new TaskFactory().StartNew(()=>
            {
                new Task(() => Work(), TaskCreationOptions.AttachedToParent).Start();
                new Task(() => Work(), TaskCreationOptions.AttachedToParent).Start();
                new Task(() => Work(), TaskCreationOptions.AttachedToParent).Start();
                new Task(() => Work(), TaskCreationOptions.AttachedToParent).Start();
                
            });
            task.ContinueWith(t=>
            {
                watch.Stop();
                Console.WriteLine(watch.Elapsed);
            },TaskContinuationOptions.OnlyOnRanToCompletion);

El código de Work es el siguiente  :

 

        static void Work()
        {
            //create batch and iterations specs
            int maxDocuments = 125000;
            int batchSize = 100;
            int iterations = maxDocuments / batchSize;

            int index = 0;
            var batch = new BsonDocument[batchSize];

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

            for (int i = 0; i < iterations; i++)
            {

                while (index < batchSize)
                {
                    batch[index] = new BsonDocument()
                    {
                        {"_id",Guid.NewGuid().ToByteArray()},
                        {"s","XXXXXXXXXXXXXXXXXXXX"}
                    };
                    ++index;
                }

                index = 0;
                collection.InsertBatch(batch, insertOptions);
            }
        }

Venga, vamos a hacer la prueba…. [redoble de tambores…….] el resultado es …. 1,6 segundos, gracias a las capped collections y al prefetch del tamaño  y número de documentos he aumentado el rendimiento enormemente, de 3,5 a 1,6 segundos en insertar 500K documentos…

…….Sigo preocupado…..

 

Las malas lenguas me han dicho que pablo bajará ese tiempo…. y ya, lo único que se me ocurre es montar un sharding y no tengo muy claro que eso NO sea hacer TRAMPAS….

Nos leemos,

Unai

Published 20/11/2011 14:26 por Unai
Comparte este post:
http://geeks.ms/blogs/unai/archive/2011/11/20/hot-inserciones-masivas-en-sql-sersver-vs-mongo-db-iii.aspx

Comentarios

# re: HOT:Inserciones masivas en Sql Sersver vs Mongo DB ( III)

Esto está de lo más entretenido.

No tengo ni idea de mongodb y seguro que ya lo has probado pero, ¿no es muy pequeño el tamaño del batch? Me haría mucha ilusión que ganaras al Sql ;-)

Sunday, November 20, 2011 10:20 PM por Juanma

# re: HOT:Inserciones masivas en Sql Sersver vs Mongo DB ( III)

En cualquier caso 1,6 segundos es increíble, solo la generación de la colección, la apertura y cierre de la conexión ya tomara gran parte de este tiempo.

Un saludo.

Monday, November 21, 2011 3:35 AM por Juan Irigoyen

# re: HOT:Inserciones masivas en Sql Sersver vs Mongo DB ( III)

Estamos en ascuas!!!

Monday, November 21, 2011 8:08 AM por Kash

# re: HOT:Inserciones masivas en Sql Sersver vs Mongo DB ( III)

Juanma: Ya he probado distintos valores de batch y paralelismo y no he ganado nada, tendria que haber hecho alguna gráfica pero soy un poco vago sorry..

Unai

Monday, November 21, 2011 12:12 PM por Unai

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

Sunday, December 11, 2011 11:50 AM por Josue Yeray