Content Query Web Part vs. Custom Aggregation Web Part
Best Practices, Content Query Web Part, Development, Performance, SharePoint, WCMDuring the Office Developer Conference 2008 I have attended a great presentation on high performance SharePoint 2007 solutions by Andrew Connell. And although I've heard a few times before that if you care for performance of your solution, and obviously you should if you're responsible for delivering Internet-facing Publishing Sites in SharePoint 2007, it became clear to me once again: one of the best aggregation solutions out there you should use is the Content Query Web Part… or isn't it?
The Content Query Web Part allows you to aggregate content: from a particular List, Site or the whole Site Collection. You can query the content of particular type and filter it using various criteria. As it produces XML you can separate the presentation layer from the data layer and format the output using XSL. Although highly customizable, the Content Query Web Part misses some flexibility and a few common features, each aggregation solution should have like for example paging and filtering the contents using query string parameters. Lack of XSL knowledge combined with the other reasons I have just named, are reason enough for many SharePoint 2007 developers to develop their own alternatives of the CQWP leveraging the exact functionality and flexibility as defined by the requirements. But what about the performance? Can custom aggregation solutions be compared with the Content Query Web Part? To answer this question I have set up a test case.
What's in the deck
If you have attended Andrew's presentation or at least had a look at the most common aggregation approaches in SharePoint 2007, you know that most of the developers use one of the following to aggregate SharePoint 2007 data:
- Enumerating collections
- obtaining a SPListItemCollection by using SPQuery
- obtaining a DataTable by using GetDataTable() and SPQuery
- obtaining data by using PortalSiteMapProvider
Having a look at the SDK you will find two more possibilities: Microsoft.SharePoint.Publishing.CrossListQueryInfo class (used by the Content Query Web Part, available with MOSS only) and the Microsoft.SharePoint.SPSiteDataQuery class available with WSS. As I have found very little information on the Internet about the performance of the different approaches (except the great paper by Steve Peschka called Working with large lists in Office SharePoint® Server 2007) I have decide to test some of them.
The Concept
In his paper Steve has presented the results based on huge lists containing over 150k items. It is really extreme, if you ask me, so I have decided to scale it down somehow to something you could achieve little more likely and yet with three zeroes: list of 2002 items. To create these items I have used the Imtech Test Content Generator – a tool I have created some time ago which allows you to create many items at once and fill them with content of your choice. So I have created 2000 news messages with a title and a paragraph of Lorem ipsum content.
To make it all a bit more difficult for SharePoint and the Web Parts I have decided to run the following query: I wanted only items of which the title started with "TestNews" (the list had 1002 other items with names that didn't match), have them sorted descending on title and getting the overview of the first 100 of them. In other words:
<Query> <OrderBy> <FieldRef Name="Title" Ascending="False" /> </OrderBy> <Where> <BeginsWith> <FieldRef Name="Title" /> <Value Type="Text">TestNews</Value> </BeginsWith> </Where> </Query>
The Web Part
As I wanted to test a few approaches I needed not one Web Part but four actually:
- CrossListQueryInfo
- PortalSiteMapProvider
- SPQuery with SPList
- SPSiteDataQuery
I have decided to create a Base Web Part which would provide the base functionality for the specific Web Parts like CAML Query, View Fields etc.
Another thing I definitely wanted to use in my test was the concept of XML/XSL. The Content Query Web Part uses it and I think it's great. It allows the power users to modify the presentation layer without the need of a deployment of a new Web Part. I wanted to make my Web Parts reuse this concept and produce XML output. As the XSL processing has no impact of the performance of the particular query method so I have decided not to make it a part of the test.
Also to see the impact of Application Pool recycles on the performance I have decided to load each Web Part a few times: first after an Application Pool recycle, then full refresh (also known as CTRL+F5) and then some few more refreshes (F5).
The Results
It seems like the SPSiteDataQuery and SPQuery classes perform the best of all the approaches I have tested. The way the PortalSiteMapProvider performed in the test has really disappointed me. It has already scored that poor and still what you get is the SiteMapNodeCollection which you will have to enumerate in order to get the desired XML output.
But let's compare our winners to the Content Query Web Part:
Conclusion? Custom Aggregation Solutions are crappy. But there is one more Web Part left in the deck:
Although the initial duration of the query was pretty high I provide you the detailed view to get more information on the regular query time of both Web Parts (starting on the No Cache Reload):
It seems that there is something better than the Content Query Web Part. So what is that Aggregation Web Part+?
Aggregation Web Part+
In case you didn't know SharePoint provides you two base classes for developing custom Web Parts: System.Web.UI.WebControls.WebParts.WebPart and Microsoft.SharePoint.WebPartPages.WebPart. In most cases you will use the first one which is the WebPart class known from ASP.NET. It is the recommended way for developing Web Parts for SharePoint 2007. But there are cases when you will need to pull out the Microsoft.SharePoint.WebPartPages.WebPart class to do the job.
The Microsoft.SharePoint.WebPartPages.WebPart bases on the System.Web.UI.WebControls.WebParts.WebPart class itself and enhances it with some extra functionality for connected Web Parts, client-side programming and… data caching!
In case you haven't noticed the Content Query Web Part is a WSSv3 Web Part itself. It uses some way more complex caching model than the one introduced by the SharePoint Web Part, which very likely gives the performance boost even at the first load. Still knowing that there is something which could help you creating a custom aggregation solution of great performance works for me.
The Aggregation Web Part+ I have used for the last test is exactly the same SPSiteDataQuery Web Part as used in the first test. The only difference is that in now inherits from the Microsoft.SharePoint.WebPartPages.WebPart class and it stores the output of the query in cache provided by the base class.
It seems like the test Web Part I have made works better than the Content Query Web Part but don't forget that I didn't implement the XSL transforming yet. Also, as far as we are now, you could be using the CQWP as well to achieve exactly the same result. As soon as you will add that enhanced functionality you want, your Web Part might get heavier and the performance might decrease.
Summary
Performance is one of the most important success factors of Internet facing web sites. SharePoint 2007 provides many mechanisms which help you achieve great performance even within highly dynamic pages. One of such solutions is the Content Query Web Part. It is a highly customizable Web Part and it provides solution for the most common challenges. Still there might be situations when you will need even more flexibility than CQWP can offer you. If that day comes, you know that you should reach for the Microsoft.SharePoint.WebPartPages.WebPart class.
















March 22nd, 2008 at 8:05 pm
Hi Waldek,
thank you for taking the time to do some detailed analysis about this matter!
Cheers,
Robin
March 22nd, 2008 at 10:41 pm
You're welcome
March 25th, 2008 at 10:57 am
Hi Waldek,
Interesting article. For SPS 2003 (which had not something like a site query thingy), we often used the SharePoint Search for generating overviews. For example, get all the agenda items in calendar lists.
I wonder how this approach will perform in MOSS 2007 compared with the methods you describe.
Anyway, nice article!
Mart
March 25th, 2008 at 11:33 am
Thank you for your comment Mart. On one hand not everyone has access to/uses search while developing Publishing Sites on SharePoint 2007. That's why it didn't show up in my test case in the first place. On the other hand it is definitely a plausible approach to use Search for data aggregation. I haven't researched the Search mechanism yet, but will definitely give it a try. Thanks for the tip!
April 7th, 2008 at 3:26 am
Which overload did you use on the CrossListQueryCache.GetSiteData routine. I ask because the overloads work differently. For example if you just used the CrossListQueryCache.GetSiteData(SPWeb) that is just the SPWeb.GetSiteData.
I'm asking because the numbers for CrossListQueryCache seem odd. I would have expected them to be the same as either SPWeb.GetSiteData or the Content By Query web part.
April 7th, 2008 at 6:17 am
Hello Jeff,
Thank you for your comment.
I have indeed used the GetSiteData method as it's the only method available in the CrossListQueryCache to aggregate data. The results have surprised me as well. Because the CrossListQueryCache class is being used by the Content Query Web Part I expected comparable results – just like you. Unfortunately looking at how the Content Query Web Part works didn't take me any further. So any suggestions are welcome!
May 23rd, 2008 at 3:19 pm
Nice article.
I'm in the process of needing to take something like the content query web part but add a little more functionality to it. I need to add a more complex query than it by default it allows.
Initially I have set out by inheriting from the Content Query Web Part itself and are building on that. Would you recommend this as being an OK method?
Secondly if there are such positives to be gained from using the SharePoint base web part why do Microsoft recommend against doing such a thing?
Thirdly, any chance your test files from the above could be published for download?
Many thanks
May 23rd, 2008 at 5:00 pm
If it's only query that you need to extend, you could try using the QueryOverride property. It basically allows you to use raw CAML query. The downside is, the end users won't be able to use the GUI to modify the query, unless you extend the standard CQWP and add an extra field to the ToolPart which will expose the QueryOverride property.
Extending the CQWP with the missing functionality is definitely a way to go. We have seen such approaches in many scenario's including the MSIT web site. Also Andrew Connell (MOSS MVP) shows CQWP customization using that approach.
As for the WSS Web Part, I think that it's all about compatibility. Yes, the WSS Web Part provides some extra functionality but the reusability is less comparing to the ASP.NET Web Part.
The test files: unfortunately, some time ago my hard drive has crashed. It contained the only copy of the test Web Parts. I've been thinking of rebuilding the whole case, but there are some other projects I have to work on. I would still like to answer your questions regarding the article.
May 27th, 2008 at 3:27 pm
That's excellent, much appreciated.
It seems I have chosen the correct route this time. Extending the CQWP and adding a few extra fields to allow customization. I will then use the values to build a CAML query and set the QueryOverride property to the built CAML.
Thanks for your reply and advice.
May 27th, 2008 at 4:30 pm
You're welcome, TJ. Good luck