Sunday, August 24, 2008

There have been quite a few questions about performance lately on our forums, that is, new users coming to our site and asking "How fast is EntitySpaces" or "How does it compare to architecture 'X' " and it's been our plan to do some investigation into this. Then we saw a POST on DotNetKicks regarding SubSonic's performance tests and wondered how EntitySpaces stacked up. We ran some tests and found an issue in that we were creating a needless transaction in some cases when saving single entities. A transaction was blindly being created to cover the case of a hierarchical save. However, we now detect whether or not we have other objects to save, and if not, we don't create a transaction. This really increased our performance along with a few other changes. We also made some performance enhancements in how our collection saves work. Now, it's important to state that you can not get these performance numbers in the current release. However, the performance enhancements have been made and will be in the next maintenance release to be pushed in less than two weeks. The good news is the performance enhancements will be realized no matter what database you are running against.

We decided to take the SubSonic examples from the post above and literally recreate them in the EntitySpaces syntax and do a comparison. The tests were performed on a single computer with SQL 2005 hosting the Northwind database. Both the SubSonic and EntitiySpaces tests were run on the same machine, against the same database, and both using dynamic SQL (and not stored procedures). Here are the tests and timings. We loaded a single entity from the database before the timings began to eliminate any first time startup issues such as assembly loads and configuration file reads.

All times are in mm:ss (minutes and seconds)

Test 1

This test creates an order and an order detail record saving them both. This is done in a loop for a given number of iterations.

Test 1 Results (at different iterations)

     10,000 Iterations     100,000 Iterations   1,000,000 Iterations
EntitySpaces             0:14               2:20               24:10
SubSonic             0:20               3:21               33:21

 

TEST 1 Source













EntitySpaces ==>

// Let's save a million items shall we?
for (int i = 1; i < 1000000; i++)
{
    Orders o = new Orders();
    o.CustomerID = "ALFKI";
    o.EmployeeID = 5;
    o.Freight = 10;
    o.OrderDate = DateTime.Now;
    o.RequiredDate = DateTime.Now;
    o.ShipAddress = "Somwhere, Someday";
    o.ShipCity = "City";
    o.ShipCountry = "US";
    o.ShipName = "Shipper";
    o.ShippedDate = DateTime.Now;
    o.ShipPostalCode = "99999";
    o.ShipRegion = "KS";

    o.Save();

    //OrderDetail detail = new OrderDetail();
    OrderDetails detail = new OrderDetails();
    detail.OrderID = o.OrderID;
    detail.ProductID = 13;
    detail.Quantity = 1;
    detail.UnitPrice = 100;

    detail.Save();
}









SubSonic ==>

// Let's save a million items shall we?
for (int i = 1; i < 1000000; i++)
{
    Order o = new Order();
    o.CustomerID = "ALFKI";
    o.EmployeeID = 5;
    o.Freight = 10;
    o.OrderDate = DateTime.Now;
    o.RequiredDate = DateTime.Now;
    o.ShipAddress = "Somwhere, Someday";
    o.ShipCity = "City";
    o.ShipCountry = "US";
    o.ShipName = "Shipper";
    o.ShippedDate = DateTime.Now;
    o.ShipPostalCode = "99999";
    o.ShipRegion = "KS";

    o.Save("me");

    OrderDetail detail = new OrderDetail();
    detail.OrderID = o.OrderID;
    detail.ProductID = 13;
    detail.Quantity = 1;
    detail.UnitPrice = 100;

    detail.Save("me");
}

 

Note that on the above test at 1 million iterations with 2 inserts per iteration EntitySpaces was inserting 1,379 records per second.

2,000,000 (inserts) / 1,450 (seconds) = 1,379 (inserts per second)

 

Test 2

This test loops through a million objects loading them one by one using the single entity class.
We are reading a million records with ids 7080773 through 8080773.

Test 2 Results

                          1,000,000 Entity Reads
EntitySpaces                                       6:18
SubSonic                                       7:05

 

TEST 2 Source



EntitySpaces ==>

for (int i = 7080773; i < 8080773; i++)
{
    Orders o = new Orders();
    o.LoadByPrimaryKey(i);
}


SubSonic ==>

for (int i = 7080773; i < 8080773; i++)
{
    Order o = new Order(i);
}

 

Test 3

This test loops through a million objects loading them 10 at a time into a collection class.
We are reading a million records with ids 7080773 through 8080773.

Test 3 Results

                          1,000,000 Collection Reads
EntitySpaces                                        08:53
SubSonic                                        13:47

 

TEST 3 Source



EntitySpaces ==>

for (int i = 7080773; i < 8080773; i++)
{
    int nextTen = i + 10;

    OrdersCollection oc = new OrdersCollection();
    oc.Query.Where(oc.Query.OrderID.Between(i, nextTen));
    oc.Query.Load();
}


SubSonic ==>

for (int i = 7080773; i < 8080773; i++)
{
    int nextTen = i + 10;
    OrderCollection coll = new Select().From<Order>().Where("orderid")
        .IsBetweenAnd(i, nextTen).ExecuteAsCollection<OrderCollection>();
}

 

EntitySpaces has always stacked up well in reports sent to us by users and upon our next release our customers will have even better performance. We have also added the ability to turn our Dynamic Query's into DataReaders for even higher performance in certain scenarios as outlined in this blog post. We know it's controversial to publish performance results but we believe we have treated each architecture fairly and will publish the testing harness when we publish our next ES2008 maintenance release. SubSonic, NHibernate, and other architectures are fine architectures, this post was merely to head off the inevitable questions heading our way.

EntitySpaces

From mobile devices to large scale enterprise solutions in need of serious transaction support, EntitySpaces can meet your needs. Whether you’re writing an ASP.NET application with medium trust requirements, a Mono application, or a Windows.Forms application, the EntitySpaces architecture is there for you. EntitySpaces is provider independent, which means that you can run the same binary code against any of the supported databases. EntitySpaces is available in both C# and VB.NET. EntitySpaces uses no reflection, no XML files, and sports a tiny foot print of less than 200k. Pound for pound, EntitySpaces is one tough, dependable .NET architecture.

The EntitySpaces Team
--

EntitySpaces LLC
Persistence Layer and Business Objects for Microsoft .NET
http://www.entityspaces.net

Comments are closed.