Performance comparison between DBreeze and STSdb

Jan 17, 2013 at 10:21 AM
Edited Jan 17, 2013 at 10:41 AM

Environment: Thinkpad T410, Intel Core i5 M520 2.4GHz  + 6GB RAM + Micron SSD M4-CT128 (500Mb/200Mb)

 

Test 1: 1 million write and read

DBreeze

DBreeze write - 00:00:05.9167766

DBreeze read - 00:00:00.0173734

Files size: 71MB

STSdb

STSdb write - 00:00:06.1857345

STSdb read - 00:00:00.0197155

Files size: 52MB

 

DBreeze is slightly faster than STSdb in both write and read, but the file size is 36% more than STSdb

 

Test 2: repeat same 1 million write and read (run again)

DBreeze

DBreeze write - 00:00:29.2614818

DBreeze read - 00:00:00.0181800

Files size: 152MB

 

STSdb

STSdb write - 00:00:06.1785519

STSdb read - 00:00:00.0166873

Files size: 104MB

 

DBreeze is significantly slower while trying to insert records with same key, while STSdb is consistent with fresh insert, but the file size is 46% more than STSdb

 

Test 3: 1 million write and read without serialization for STSdb


DBreeze

DBreeze write - 00:00:05.9157415

DBreeze read - 00:00:00.0171783

Files size: 71MB

 

STSdb

STSdb write - 00:00:05.5962032

STSdb read - 00:00:00.0292057

Files size: 12MB

 

DBreeze is slightly faster in write and 1x faster in read than STSdb, but the file size is 5x times more than STSdb. As we can see here, STSdb has built-in compression and achieve a lot less disk space usage, without the need for custom serializer, the usage is more straightforwrd.

 

 

Test code for test 1 and test 2:

 

using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using DBreeze;
using DBreeze.DataTypes;
using STSdb.Data;
using STSdb.Files;
using STSdb.Plan;

namespace ConsoleApplication18
{
    class Program
    {
        private const ulong count = 1000000;

        static void Main(string[] args)
        {

            TestDBreeze();
            Console.WriteLine();
            TestSTSdb();
            Console.Read();
            Console.WriteLine("done");
        }

        private static void TestDBreeze()
        {
            var w = new Stopwatch();
            Console.WriteLine("DBreeze");
            Console.WriteLine("DBreeze write");
            w.Restart();
            using (var engine = new DBreezeEngine(@"C:\Temp\DBreeze"))
            {
                using (var tran = engine.GetTransaction())
                {
                    //DBreeze.Utils.CustomSerializator.Serializator = MySerializer;
                    //DBreeze.Utils.CustomSerializator.Deserializator = MyDeserializer;

                    try
                    {
                        for (ulong i = 0; i < count; i++)
                        {
                            var foo = new Foo { Double = i * 1.1, Long = (ulong)i, Name = "Name " + i, Time = DateTime.Now, Value = (int)i };
                            tran.Insert<ulong, byte[]>("t1", i, foo.Serialize());
                        }
                        tran.Commit();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                    }
                    w.Stop();
                    Console.WriteLine(w.Elapsed);
                    Console.WriteLine("DBreeze read");
                    w.Restart();
                    var data = tran.SelectForward<ulong, byte[]>("t2").Take(100);
                    foreach (var item in data)
                    {
                        var foo = item.Value.Deserialize();
                        Console.WriteLine(item.Key + "," + foo.Double);
                    }
                }
            }
            w.Stop();
            Console.WriteLine(w.Elapsed);
        }

        private static void TestSTSdb()
        {
            var w = new Stopwatch();

            Console.WriteLine("STSdb");
            Console.WriteLine("STSdb write");
            w.Start();
            using (var repository = StorageEngine.FromFile(@"c:\temp\STSdb\test.stdb"))
            {
                var locator = new Locator("t1");
                var table = repository.Scheme.CreateOrOpenXTable<ulong, byte[]>(locator);
                for (ulong i = 0; i < count; i++)
                {
                    var foo = new Foo { Double = i * 1.1, Long = (ulong)i, Name = "Name " + i, Time = DateTime.Now, Value = (int)i };
                    //table[i] = foo;
                    table[i] = foo.Serialize();
                }
                table.Commit();

                w.Stop();
                Console.WriteLine(w.Elapsed);
                Console.WriteLine("STSdb read");
                w.Restart();
                table = repository.Scheme.OpenXTable<ulong, byte[]>(locator);
                var actualCount = repository.Scheme.Count;
                for (ulong i = 0; i < actualCount; i++)
                {
                    var foo = table[i].Deserialize();
                }
            }
            w.Stop();
            Console.WriteLine(w.Elapsed);
        }
    }

    public class Foo
    {
        public string Name { get; set; }
        public int Value { get; set; }
        public DateTime Time { get; set; }
        public ulong Long { get; set; }
        public double Double { get; set; }
    }

    public static class Extensions
    {
        public static byte[] Serialize(this Foo Item)
        {
            byte[] content;
            using (var buffer = new MemoryStream())
            {
                using (var writer = new BinaryWriter(buffer))
                {
                    writer.Write(Item.Double);
                    writer.Write(Item.Long);
                    writer.Write(Item.Name);
                    writer.Write(Item.Time.ToString());
                    writer.Write(Item.Value);
                    writer.Close();
                }
                content = buffer.ToArray();
            }
            return content;
        }

        public static Foo Deserialize(this byte[] Content)
        {
            Foo item = new Foo();
            using (var buffer = new MemoryStream(Content))
            {
                using (var reader = new BinaryReader(buffer))
                {
                    item.Double = reader.ReadDouble();
                    item.Long = reader.ReadUInt64();
                    item.Name = reader.ReadString();
                    item.Time = DateTime.Parse(reader.ReadString());
                    item.Value = reader.ReadInt32();
                    reader.Close();
                }
            }
            return item;
        }
    }
}

 

 

Test code for test 3:

 

using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using DBreeze;
using DBreeze.DataTypes;
using STSdb.Data;
using STSdb.Files;
using STSdb.Plan;

namespace ConsoleApplication18
{
    class Program
    {
        private const ulong count = 1000000;

        static void Main(string[] args)
        {

            TestDBreeze();
            Console.WriteLine();
            TestSTSdb();
            Console.Read();
            Console.WriteLine("done");
        }

        private static void TestDBreeze()
        {
            var w = new Stopwatch();
            Console.WriteLine("DBreeze");
            Console.WriteLine("DBreeze write");
            w.Restart();
            using (var engine = new DBreezeEngine(@"C:\Temp\DBreeze"))
            {
                using (var tran = engine.GetTransaction())
                {
                    //DBreeze.Utils.CustomSerializator.Serializator = MySerializer;
                    //DBreeze.Utils.CustomSerializator.Deserializator = MyDeserializer;

                    try
                    {
                        for (ulong i = 0; i < count; i++)
                        {
                            var foo = new Foo { Double = i * 1.1, Long = (ulong)i, Name = "Name " + i, Time = DateTime.Now, Value = (int)i };
                            tran.Insert<ulong, byte[]>("t1", i, foo.Serialize());
                        }
                        tran.Commit();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                    }
                    w.Stop();
                    Console.WriteLine(w.Elapsed);
                    Console.WriteLine("DBreeze read");
                    w.Restart();
                    var data = tran.SelectForward<ulong, byte[]>("t2").Take(100);
                    foreach (var item in data)
                    {
                        var foo = item.Value.Deserialize();
                        Console.WriteLine(item.Key + "," + foo.Double);
                    }
                }
            }
            w.Stop();
            Console.WriteLine(w.Elapsed);
        }

        private static void TestSTSdb()
        {
            var w = new Stopwatch();

            Console.WriteLine("STSdb");
            Console.WriteLine("STSdb write");
            w.Start();
            using (var repository = StorageEngine.FromFile(@"c:\temp\STSdb\test.stdb"))
            {
                var locator = new Locator("t1");
                var table = repository.Scheme.CreateOrOpenXTable<ulong, Foo>(locator);
                for (ulong i = 0; i < count; i++)
                {
                    var foo = new Foo { Double = i * 1.1, Long = (ulong)i, Name = "Name " + i, Time = DateTime.Now, Value = (int)i };
                    table[i] = foo;
                    //table[i] = foo.Serialize();
                }
                table.Commit();

                w.Stop();
                Console.WriteLine(w.Elapsed);
                Console.WriteLine("STSdb read");
                w.Restart();
                table = repository.Scheme.OpenXTable<ulong, Foo>(locator);
                var actualCount = repository.Scheme.Count;
                for (ulong i = 0; i < actualCount; i++)
                {
                    var foo = table[i];
                }
            }
            w.Stop();
            Console.WriteLine(w.Elapsed);
        }
    }

    public class Foo
    {
        public string Name { get; set; }
        public int Value { get; set; }
        public DateTime Time { get; set; }
        public ulong Long { get; set; }
        public double Double { get; set; }
    }

    public static class Extensions
    {
        public static byte[] Serialize(this Foo Item)
        {
            byte[] content;
            using (var buffer = new MemoryStream())
            {
                using (var writer = new BinaryWriter(buffer))
                {
                    writer.Write(Item.Double);
                    writer.Write(Item.Long);
                    writer.Write(Item.Name);
                    writer.Write(Item.Time.ToString());
                    writer.Write(Item.Value);
                    writer.Close();
                }
                content = buffer.ToArray();
            }
            return content;
        }

        public static Foo Deserialize(this byte[] Content)
        {
            Foo item = new Foo();
            using (var buffer = new MemoryStream(Content))
            {
                using (var reader = new BinaryReader(buffer))
                {
                    item.Double = reader.ReadDouble();
                    item.Long = reader.ReadUInt64();
                    item.Name = reader.ReadString();
                    item.Time = DateTime.Parse(reader.ReadString());
                    item.Value = reader.ReadInt32();
                    reader.Close();
                }
            }
            return item;
        }
    }
}
Coordinator
Jan 17, 2013 at 12:31 PM
Edited Jan 17, 2013 at 12:32 PM

In your test you use growing up key +1.

Try ulong key like this:

 

DateTime dts=new DateTime(1970,1,1);

for(int i=0;i<1000000;i++)

{

    dts = dts.AddSeconds(7);

     tran.Insert<ulong,byte>("t1",dts.Ticks,0);

}

tran.Commit();

Then try to update this table with the same values.

Try random inserts.

Then try for DBreeze "magic hash function" approach:

If you have key with growing up identity 1..2...3 etc....

you can say that keys from 1 up to 10000 stay in block 1, keys from 10001 up to 20000 in block 2 etc...

So, in the table you have only block numbers as keys as value you have the whole block of 10000 keys and values, such serialized and compressed Dictionary.

If you store every key separately and every value is of 50 bytes - there is nothing to compress.

but if you take block (8(key length)+50(middle value length)) * 10000 (pairs in the block) = 580KB compress it, probably you will receive 12KB.

Going further, try make Commit after every your insert - emulate standard data accumulation behavior of the program (not always you insert million of records in bulk) and compare sizes of both databases.