Inefficient iteration of list items in .ashx http handler code

Feb 24, 2009 at 12:25 AM
Edited Feb 24, 2009 at 12:26 AM
This project is really cool, but I did see one thing in the Tags.ashx that is very resource-intensive and inefficient that you might want to change in the next build:

        using (SPSite site = SPContext.GetContext(HttpContext.Current).Site)
            foreach (SPWeb web in site.AllWebs)

                string tag = HttpContext.Current.Request.QueryString["Tag"];

                foreach (SPList list in web.Lists)

                    foreach (SPListItem listItem in list.Items)

                        if (listItem.Fields.ContainsField("Tags"))

You should never iterate over a list in this manner, as it can potentially create huge hits to the content db and IIS worker process memory consumption, especially if the site has many lists, some with many list items in them.  Please consider updating the code to use SPQuery to get an SPListItemCollection object instead, something in-line with these articles' recommendations.

You should change this to use CAML and SPQuery object to get a DataSet from the site instead of iterating through all the subwebs of the site collection, and then over each of the lists, as you have done above.  The way you've coded this here is fine in development on a small site with no data, but could be lead to a lot of time out errors and web app pool recycles on a production site.

If you need it to go over an entire site collection, you might want to use the SPSiteDataQuery object, to do something like this instead:

DataTable dt = new DataTable();
       using (SPSite site = new SPSite(SPContext.GetContext(HttpContext.Current).Site.ID))
using(SPWeb web = site.OpenWeb())
SPSiteDataQuery query = new SPSiteDataQuery();
            query.Webs = "<Webs Scope=\"SiteCollection\" />" ; //sets scope of query to entire site collection - could also limit to recursively search below an SPWeb in other context
            query.Lists = "<Lists ServerTemplate=\"4\" MaxListLimit=\"0\" />"; //template ID for custom list = 4
            query.ViewFields = "<FieldRef Name=\"Tags\" Nullable=\"FALSE\" />;
            query.RowLimit = 10000; //if you don't explicitly set the row limit, underlying sql query will default to top millions of rows instead...
            dt = web.GetSiteData(query); //returns DataTable object
return dt;

Then you can do something with the DataTable object instead, or even cache that.

Great web parts - where is the Tag Cloud web part from the screencast about using the TagSuggestion web part?