I recently had to clean a huge (113 000 rows) document library. The first question that must come in mind is : Why was it so big ? Well, someone thought it was beter to store data in lots of XML files instead of in a classic list.

The second question is: How ?

First, you have to understand that you can’t use a DeleteAll() method, it doesn’t exist. You must fetch data by little packet of rows. If you try to get everything, you will have a OutOfMemoryException.

I can’t give you the final app as I am not sure that I have the right to, but I can give you the core sourcecode:

First of all, you want to avoid the memory exception problem. So you will cut your results in little packets of 100 rows, that’s pretty simple:

// We get everything but we limit the result to 100 rows
SPQuery q = new SPQuery();
q.RowLimit = 100;

// We get the results
SPListItemCollection coll = list.GetItems( q );


Then, what you could do is delete each item one by one:

foreach( SPListItem item in cColl ) {
item.Delete();
}


But it’s soooo freaking slow. On a production server, we had something like 1 delete per second.

What you need to use is a CAML batch delete, this method builds a CAML delete batch :

private static String BuildBatchDeleteCommand( SPList list, SPListItemCollection coll ) {
StringBuilder sbDelete = new StringBuilder();
sbDelete.Append( "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Batch>" );

// We prepare a String.Format with a String.Format, this is why we have a {{0}}
string command = String.Format( "<Method><SetList Scope=\"Request\">{0}</SetList><SetVar Name=\"ID\">{{0}}</SetVar><SetVar Name=\"Cmd\">Delete</SetVar><SetVar Name=\"owsfileref\">{{1}}</SetVar></Method>", list.ID );
foreach ( SPListItem item in coll ) {
sbDelete.Append( string.Format( command, item.ID.ToString(), item.File.ServerRelativeUrl ) );
}
sbDelete.Append( "</Batch>" );
return sbDelete.ToString();
}


With that method, we could delete 100 rows in 23 seconds. Still, you can’t expect magic with Sharepoint, everything around Sharepoint is slow.

The final main code should look a little bit like that:

// While there's something left
while ( list.ItemCount >  ) {

// We get everything but we limit the result to 100 rows
SPQuery q = new SPQuery();
q.RowLimit = 100;

// We get the results
SPListItemCollection coll = list.GetItems( q );

// We process a CAML batch
String batch = BuildBatchDeleteCommand( list, coll );

// We execute it
web.ProcessBatchData( batch );

list.Update();
}


Note SPWeb::ProcessBatchData returns a String, if your code doesn’t work, it could help you find out why. This is the only way, because a wrong batch won’t throw any exception. Keep that in mind.