Sunday, July 27, 2014

RavenDB 2.5 vs 3.0 Write Performance (so far)

Is Voron out performing Esent in RavenDB 3.0?

...not yet, at least in terms of write speed. I ran a few tests on my home machine to compare the write and indexing speeds of Raven 2.5 (build 2908) against Raven 3.0 (build 3358). Unfortunately the results were not encouraging. However it is worth pointing out that the Raven team did save their performance updates for last when releasing Raven 2.5, so I do expect that this will improve before we see an RC.

Test Results

Here are the results of my (little) performance tests:

Document Count RavenDB 2.5 RavenDB 3.0 Difference
Elapsed Import Time Elapsed Index Time Elapsed Import Time Elapsed Index Time Import Percent Index Percent
0 - 100k 0:57.48 1:41.45 1:08.59 1:25.39 -19.33% 15.82%
100k - 200k 1:02.68 1:34.85 1:10.87 1:35.65 -13.08% -0.84%
200k - 300k 1:00.34 2:17.84 1:12.94 1:47.20 -20.89% 22.22%
300k - 400k 1:00.85 1:38.59 1:13.46 1:45.61 -20.73% -7.12%
400k - 500k 1:02.03 1:38.70 1:12.03 1:58.51 -16.12% -20.07%

Test Index

Here is the test index:

from t in docs.PerfTesters
select new
{
   t.FullName,
   t.Age,
   t.RandomText,
   t.NotSoRandomText
}
  • Fields
    • FullName
      (Analyzed, Lucene.Net.Analysis.Standard.StandardAnalyzer, Lucene.Net)
    • RandomText
      (Analyzed, Lucene.Net.Analysis.Standard.StandardAnalyzer, Lucene.Net)
    • NotSoRandomText
      (Analyzed, Lucene.Net.Analysis.Standard.StandardAnalyzer, Lucene.Net)

Test Code

Here is the code to run the tests:

public class RavenComparison
{
    [Fact]
    public void PerfTest()
    {
        using (var store = new DocumentStore
        {
            DefaultDatabase = "Test",
            Url = "http://localhost:8080/"
        })
        {
            store.Initialize();
 
            var sw1 = Stopwatch.StartNew();
            var sw2 = Stopwatch.StartNew();
 
            var id = 0;
 
            for (var i = 0; i < 100; i++)
            {
                using (var bulkInsert = store.BulkInsert())
                {
                    for (var j = 0; j < 1000; j++)
                    {
                        var doc = PerfTesterFactory.Create(++id);
                        bulkInsert.Store(doc);
                    }
                }
            }
 
            sw1.Stop();
 
            Console.WriteLine("Write Count: " + id);
            Console.WriteLine("Write Elapsed: " + sw1.Elapsed);
            Console.WriteLine(
                "Write ElapsedMilliseconds: " 
                + sw1.ElapsedMilliseconds);
 
            int? resultCount = null;
            while (!resultCount.HasValue)
            {
                resultCount = Query(store);
            }
 
            sw2.Stop();
 
            Console.WriteLine("Read Count: " + resultCount.Value);
            Console.WriteLine("Read Elapsed: " + sw2.Elapsed);
            Console.WriteLine(
                "Read ElapsedMilliseconds: " 
                + sw2.ElapsedMilliseconds);
        }
    }
 
    private int? Query(DocumentStore store)
    {
        try
        {
            using (var session = store.OpenSession())
            {
                var results = session.Advanced
                    .LuceneQuery<PerfTester>("Tester")
                    .Where("FullName: Tom")
                    .WaitForNonStaleResults()
                    .ToList();
 
                return results.Count;
            }
 
        }
        catch (TimeoutException)
        {
            return null;
        }
    }
}
 
public static class PerfTesterFactory
{
    private static readonly Random Random = new Random();
 
    private static readonly IList<string> FirstNames = new[]
    {
        "Tom", "Thomas", "Matt", "Matthew", "Zach", "Zachery",
        "Rick", "Richard", "Bill", "William"
    };
 
    private static readonly IList<char> MiddleInitials = new[]
    {
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'
    };
 
    private static readonly IList<string> LastNames = new[]
    {
        "Software", "Engineer", "Associate", "MidLevel", 
        "SeniorOne", "SeniorTwo", "Lead", "Principal",
        "Director", "Chief"
    };
 
    private static readonly IList<string> NotSoRandomWords = LastNames
        .Concat(FirstNames)
        .ToList();
 
    public static PerfTester Create(int id)
    {
        return new PerfTester
        {
            FirstName = FirstNames.GetRandom(),
            MiddleInitial = MiddleInitials.GetRandom(),
            LastName = LastNames.GetRandom(),
            Age = Random.Next(0, 100),
            Gender = id%2 == 0 ? GenderType.Male : GenderType.Female,
            RandomText = GetRandomText(),
            NotSoRandomText = GetNotSoRandomText()
        };
    }
 
    private static string GetRandomText()
    {
        var l = new List<string>();
        for (var i = 0; i < 50; i++)
        {
            var s = Guid.NewGuid().ToString().Split('-');
            l.AddRange(s);
        }
        return string.Join(" ", l);
    }
 
    private static string GetNotSoRandomText()
    {
        var l = new List<string>();
        for (var i = 0; i < 250; i++)
        {
            var s = NotSoRandomWords.GetRandom();
            l.Add(s);
        }
        return string.Join(" ", l);
    }
 
    private static T GetRandom<T>(this IList<T> list)
    {
        var i = Random.Next(0, list.Count);
        return list[i];
    }
}
 
public class PerfTester
{
    public string FirstName { get; set; }
    public char MiddleInitial { get; set; }
    public string LastName { get; set; }
 
    public string FullName
    {
        get
        {
            return string.Format(
                "{0}, {1} {2}", 
                LastName, 
                FirstName, 
                MiddleInitial);
        }
    }
 
    public string RandomText { get; set; }
    public string NotSoRandomText { get; set; }
    public GenderType Gender { get; set; }
    public int Age { get; set; }
}
 
public enum GenderType
{
    Male,
    Female
}

Enjoy,
Tom

No comments:

Post a Comment

Real Time Web Analytics