Code Highlighting

Monday, August 13, 2012

Sorting a GridView bound to an ObjectDataSource - Speed

Just a short bit of code that dates back to ancient times. I use a lot of GridViews bound to ObjectDataSources for database back-end updating modules. To enable sorting those, you need to define the SortParameterName attribute on the ObjectDataSource, and create an overload on your SelectMethod to takes a string parameter of the name you set. No problem.
The issue is that you now need to implement the sorting yourself.
To sort these there are lots of solutions around, from going over the various sort options in a switch statement, just shipping the sort to your database, or a generic approach using Reflection.

The generic approach is clearly the most flexible, but there is drawback: the performance of reflection is pretty terrible. As soon as you have longer lists, it matters. Nobody wants to wait 10 seconds just to sort a list.
So I took the reflection approach, and implemented it using a DynamicMethod. I'm not posting the code, because it's about 300 lines (including comments), there's a download link at the end.
Using it is easy. Either import the namespace and use the extension method:


public static List<Ticket> GetAll(){
            SqlConnection cnData = new SqlConnection(Data.ConnectionString);
            List<Ticket> dbItem = new List<Ticket>();
            SqlCommand cmdData = new SqlCommand("GetAllTickets", cnData);
            
            /* Yadda yadda, whatever */
            
            return dbItem;
        }

        public static List<Ticket> GetAll(string sortExpression)
        {
            var entities = GetAll();
            
            //calls the extension method
            entities.Sort(sortExpression);

            return entities;
        }


Or just use the IComparer directly:


        public static List<Ticket> GetAll(string sortExpression){
            var entities = GetAll();
            
            entities.Sort(new Tabeoka.PropertyComparer<Ticket>(sortExpression));
            return entities;
        }


Here are the performance numbers (Core 2 Quad, 8 Gb ram. 100,000 items in list):

Sort by Int property:
  • Native method: 00.0592331 s
  • DynamicMethod: 00.2716980 s
  • Reflection: 03.6649998 s
Sort by String property:
  • Native method:  00.3787244 s
  • DynamicMethod: 00.4680498 s
  • Reflection: 03.8817182 s
It's interesting how much faster the native method is compared to the DynamicMethod for the Int property. Clearly we're paying the overhead of the boxing due to casting to object and IComparable. If you're doing lots of sorting Int, you could conceivably write a separate code path. The speed increase is still dramatic compared to Reflection.
Just two more remarks:
  • You can sort by multiple properties. 
  • I included a extension method: List<T>.Sort(string sortExpression)
Download here. Have fun. Some more MVC next time.

Menno

No comments:

Post a Comment