Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Optimizing Select Projections, Part I

DZone's Guide to

Optimizing Select Projections, Part I

In the first part of our series, we set up the problem that we'll look to solve and show you how our application is currently performing.

· Performance Zone
Free Resource

I spoke about designing for performance in my previous post and I thought it would be an interesting series of blog posts. The task I have is that we have a data source of some kind, in our case, I decided to make the task as simple as possible and define the source data as a Dictionary<string, object>, without allowing nesting of data.

We want the user to be able to provide a custom way to project data from that dictionary. Here are a few ways to do that:

select {
Nick: d.Nick,
FirstName: d.FirstName,
LastName: d.LastName
}

select {
Name: d.FirstName + " " + d.LastName,
Nick: d.Nick,
Votes: d.PlusVotes - d.NegativeVotes 
}

select {
Name: (function(d) { 
    if (d.Nick != null)
      return d.Nick; 
    return d.FirstName + " " + d.LastName; 
  })(d),
Votes: d.PlusVotes - d.NegativeVotes 
}

And here is the data source in question:

var d = new Dictionary<string, object>()
{
["FirstName"] = "Oren",
["LastName"] = "Eini",
["PlusVotes"] = 5,
["NegativeVotes"] = 3,
["Nick"] = "Ayende Rahien"
};

Obviously, the user can make the select projections as complex as they wish. But I think that these three samples give us a good representation of the complexity. We’ll also treat them a bit differently, with regards to their likelihood. So when testing, we’ll check that the first projection is run 10,000 times, then the second projection is run 5,000 times and the last projection is run 1,000 times.

With the lay of the land settled, let us see how we can get this actually working. I’m going to use Jint and solve the issue in a very brute force manner.

Here is the initial implementation:

private static void Get(string projection, Dictionary<string, object> d)
{
    var engine = new Engine();
    var start = projection.IndexOf("select", StringComparison.OrdinalIgnoreCase) +"select".Length;

    var source = "function project(d) { return " + projection.Substring(start) + "; }";
    engine.Execute(source);

    var dJs = engine.Object.Construct(new JsValue[0]);
    foreach (var o in d)
    {
        dJs.Put(o.Key, o.Value is string s ? 
            new JsValue(s) : 
            new JsValue(Convert.ToDouble(o.Value)),
            true);
    }

    var result = engine.Invoke("project", new object[] {dJs});

    // do something with the result
}

And this runs in 4.4 seconds on the 10K, 5K, 1K run.

  • 10K in 2,756 ms
  • 5K in 1,310 ms
  • 1K in 314 ms

I’m pretty sure that we can do better, and we’ll look at that in the next post.

Topics:
performance ,code optimization ,database performance ,web application performance

Published at DZone with permission of Oren Eini, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}