Friday, April 15, 2011

Never use SPList.Items.GetItemById(ID)

NEVER EVER use List.Items.GetItemById(ID) or List.Items[ID]
Use List.GetItemById(ID) instead.
Under normal conditions when there are relatively few items in a list then all will seem to go well.  However, as time goes by and the list item count increases then you could find that
your SharePoint site is grinding to a halt.  This will be characterised by the application pool growing in size.
SCENARIO
A single document library well structured with folders has 680,000 documents in it.  As per MS recommendations no single view or folder has more than 2000 items.
A custom workflow was added to the site and suddenly the application pool climbs to 11Gb and the site stops responding.  The reason? The workflow includes the statement
list.Items.GetItemById(id);
This will cause the whole list to be enumerated,

using (SPSite site = new SPSite(<a href="http://someurl">http://someurl</a>))
{
    using (SPWeb web = site.RootWeb)
    {
        // Test 1
        DateTime start = DateTime.Now;
        SPListItem item = web.GetListItem("/someitemUrl"),,);
        Console.WriteLine("Time for web.GetListItem():{0}",DateTime.Now-start);
        Console.WriteLine(item.Title);
 
        // Test 2
        start = DateTime.Now;
        item = web.Lists[item.ParentList.ID].GetItemById(item.ID);
        Console.WriteLine("Time for List.GetItemById():{0}", DateTime.Now - start);
        Console.WriteLine(item.Title);
 
        // Test 3
        start = DateTime.Now;
        Console.WriteLine("This is going to take a very very very very loooooonnnnnnnngggggggggg time! Kill it now");
        item = web.Lists[item.ParentList.ID].Items.GetItemById(item.ID);
        Console.WriteLine("Time for List.Items.GetItemById():{0}", DateTime.Now - start);
        Console.WriteLine(item.Title);
 
        // Test 4
        start = DateTime.Now;
        Console.WriteLine("This is going to take a very very very very loooooonnnnnnnngggggggggg time! Kill it now");
        item = web.Lists[item.ParentList.ID].Items[item.ID];
        Console.WriteLine("Time for List.Items[]:{0}", DateTime.Now - start);
        Console.WriteLine(item.Title);
 
    }
}
 Test 1 took 1.363194s
Test 2 took 0.0087885s (very impressive)
Test 3 and 4 failed to complete due to memory resource failure