Home > c#, Visual Studio 2005 > Performance vs. Convenience and Usability

Performance vs. Convenience and Usability

April 26, 2007

I’ve spent the past day or so tweaking a framework library that I’ve written for “optimal” usability.  It’ll be consumed by our internal developers and needs to be about as bulletproof as I can make it.  The general premise of the library is to centralize a majority of our common business logic in one place.  When that logic changes, we can update the library in a managed and controlled manner—easing a bit of the pain for updates and such (in Education, ‘business logic’ is VERY fickle).

So, I came across a decision—for many of the database lookups, do we use DataTables, Rows, and Views or move everything into generic objects and use List<T>s?

I created both and decided to do a bit of benchmarking. The underlying methods use Enterprise Library 3.0 (April 07) to connect to an Oracle 10g database.  For the example, I used teachers.  In many of our buildings, there are 100+ teachers.  My “benchmark” queries all of the teachers in the eight core high schools, approximately 939 records.  It runs these queries 100 times, thus 93900 results.

The method to create the Teacher object simply queries the database and loops through each row of the returned DataTable to build the objects.  Note, this is an additional step over simply returning a DataTable.  In the code snippet below, teacherList is a List<Teacher> generic that I’ve created to allow the users of the library to use a TeacherRoster structure rather than List<Teacher>.  The BuildTeacherRecord is an internal method that builds the object based on the DataRow provided to it.

Teacher object returns:

DataTable dt = db.ExecuteDataSet(cmd).Tables[0]; 

foreach (DataRow dr in dt.Rows) 

{ 

   teacherList.Add(BuildTeacherRecord(dr)); 

}
return teacherList;

DataTable returns:

return db.ExecuteDataSet(cmd).Tables[0];

For our benchmark, we have coded a simple method that runs each test and records the times based on a StopWatch object.

protected void runBenchmark_Click(object sender, EventArgs e)
{
 
int[] schools = { 120, 195, 160, 150, 165, 170, 180, 190 };
  int dtRows = 0;
  int objRows = 0;
  Stopwatch dtWatch = new Stopwatch();
  Stopwatch objWatch = new Stopwatch();   Response.Write(“<p>DataTable</p>”);
  for (int i = 1; i < 101; i++)
  {
    dtWatch.Start();
    foreach (int school in schools)
    {
      DataTable dt = Teachers.GetTeachersBySchoolId(school);
     dtRows += dt.Rows.Count;
    }
    dtWatch.Stop();
    Response.Write(dtWatch.ElapsedMilliseconds +
“<br/>”);
}
Response.Write(
“<p>There are “ + dtRows + ” rows.”);Response.Write(“<p>TeacherRoster object</p>”);
for (int i = 1; i < 101; i++)
{
  objWatch.Start();
  foreach (int school in schools)
  {
    TeacherRoster teacherList = Teachers.GetTeachersbySchoolId(school);
    objRows += teacherList.Count;
  }
  objWatch.Stop();
  Response.Write(objWatch.ElapsedMilliseconds +
“<br/>”);
}
Response.Write(
“<p>There are “ + objRows + ” rows.”);
}
 


The results were not really that surprising.

I ran two iterations of the benchmark: one as coded above, and one coding to clear the stopwatch (watch.Reset()) each time to get a clearer picture of each of the 100 test.

For the “Start to Finish” results (time in Milliseconds):

 

Our information provides that the object 2094 milliseconds (2.1 seconds) longer to run all 100 tests than the DataTable.  Not a significant number, but over 1000 or multiple users, it could add up.

For the individual test results (again, in milliseconds):

So, our DataTable will be +/– 55.8 of 149.24 (~93 to 205) where as our generic object collection will be +/– 32.7 of 169.0 (~136.3 to 202).  The mean of the DataTable is approximately 20 milliseconds faster that the object

So, what does this all mean?  Why do we care?

Well, I’m sure there’s a hardcore performance expert out there that just cannot fathom a wasted millisecond.  I agree.  I really do.  However, as with all things in development there are trade offs.

All of this boils down to usability.

When I want to display out the string of the Teacher’s last name, do I want to:

DataRow teacherDataRow = GetTeacherDataRow(teacherId);
teacherLastName.Text = teacherDataRow[”last_name”].ToString();

and take the hope that our consumer knows the structure of the table?

Using the object, the user can simply:

Teacher teacherObject = GetTeacherObject(teacherId);
teacherLastName.Text = teacherObject.lastName;

So, I’m wondering—has anyone found any hard evidence on performance?  What about object optimization for generics and such…?

Tags: , , ,

Categories: c#, Visual Studio 2005
  1. jh71283
    May 14, 2007 at 4:47 am

    If you use a typed datatable, then the usability is equal to using an object in your example….

    best of both worlds!

  2. May 14, 2007 at 7:05 am

    I totally agree–even more so with .NET 3.5’s DLINQ; however, one larger issue that I face is that our organization constantly mixes and matches the backend database types–and about 80% of our information is stored on Oracle.

    The above example was hitting an Oracle 10g database. VS2005, even with the ODT, is still not keen with using Oracle–at least not to the magnitude of MSSQL (that I’ve seen).

  1. No trackbacks yet.
Comments are closed.
%d bloggers like this: