Solve Item-Level Permission Performance Problems in SharePoint

29 December 2009 Categories: How To, SharePoint

Original Article: http://www.sharepointbriefing.com/spcode/article.php/3816551

By Jason Ruthkoski
April 21, 2009

Have you ever had a requirement stating that a document library needs to have item-level permissions for a large number of items? For example, perhaps you need to create a document library to house customer financial statements or invoices, giving the customers permission to access only their own items.

One approach would be to create a separate document library for each customer, and handle permissions at the library level. However, this solution would be a headache to manage. Having thousands of document libraries to handle only a few documents per library is not a reasonable approach. Besides, do you really want to have to create a new document library for each new customer?

Another approach would be to have one document library for each type of document. For this example, you would create a single document library for customer invoices containing separate folders for each customer. You could then handle permissions at the folder level. Seems reasonable, right?

The Problem

If you’ve ever tried either approach, then you probably know that item-level permissions in SharePoint can cause serious performance issues. That’s because when you create a new item in a document library and “break permissions” (stop inheriting permissions) from the parent library, SharePoint automatically copies all the permissions from the parent document library to the item level.

After breaking permissions you can call the BreakRoleInheritance function in the SharePoint API to clear out the copied parent permissions, setting its CopyRoleAssignments flag to false. However, the API does not do a mass delete of the permissions; instead, it iterates through the permission list, deleting them one by one. For example, if you have 5000 folders, it will need to delete 5000 permissions—one by one—in your new item’s access control list. That’s because each customer needs a “limited access” permission to the top-level library, which tells SharePoint that the user has permission to something at a lower level (i.e., a document or a folder). In the single-library-multiple-folder strategy, each new customer would have “limited access” permission to the top-level library and each new item would automatically copy down those limited access permissions from the library when the item was created. If you do the math, 4000 items * 4000 limited-access permissions per item equals 16 million unnecessary limited access permissions!

I tried using this strategy with a console application that imported documents; it eventually required 20 to 30 minutes for each new customer! After doing some performance testing with this approach, it turned out that the worst-case scenario for uploading 4000 to 5000 documents would have been between 2 and 3 months, which was obviously unacceptable.

So if clearing the parent-level permissions isn’t a good approach, suppose you simply set the CopyRoleAssignments flag to true? SharePoint would still break the permission inheritance of your item, but it wouldn’t clear out all the unnecessary permissions that already existed. Unfortunately, that doesn’t work well either. You might think that it wouldn’t matter whether there are extraneous limited-access permissions in each of the folders—but you’d be wrong! Leaving the extraneous permissions can cause serious performance issues when viewing the document library or adding new permissions, because it exponentially increases the number of permissions SharePoint has to iterate through to figure out what access a logged-in user has. My real-world testing showed that it would take over 15 minutes to view the documents!

So it would seem you’re between a rock and a hard place. Cleaning up the permissions when creating the folder causes your import to be slow, but if you don’t clean up the unnecessary permissions, viewing the documents will be slow. What are you supposed to do?

Luckily, there’s a neat little trick that allows you to do both. If you move a folder within a document library to another location in that library, SharePoint moves its permissions along with it. In other words, if you create a new folder in a library with zero permissions, and then move it, you won’t have to do any messy cleanup of limited-access permissions.

With that background under your belt, here’s the process:

Follow this process to solve the item-level permissions problem:

  1. Create your new document library and elect to copy and then stop inheriting permissions from the parent site. Because you’re going to handle security at the folder level, that will work fine.
  2. Clear out the permissions in your new library, which will have inherited permissions from its parent site. You can do this manually or by calling the BreakRoleInheritance API function. Either way, this operation might be a little slow if you have a lot of permissions set at the site level.
  3. Create a new folder in your library called BlankFolder and break its permissions. Because you’ve already cleared the library’s permissions, the new BlankFolder folder should now have zero permissions.
  4. In your import process, create a new folder within BlankFolder, called BlankFolder2 and break its permissions. Then use the MoveTo function in the API to move the new folder to the base level of your library. Finally, rename it to something descriptive (a customer ID works well for this example).
  5. The code should look something like this:

    SPFolder blankFolder;
    // either get or create a blank folder
    try
    {
       blankFolder = workingFolder.SubFolders[
          "BlankFolder"].SubFolders["BlankFolder2"];
    }
    catch (ArgumentException) // if blankfolder2 does not exist…
    {
       blankFolder = workingFolder.SubFolders[
          "BlankFolder"].SubFolders.Add("BlankFolder2");
       blankFolder.Item.BreakRoleInheritance(true);
       blankFolder.Update();
    }
    //Now move the new folder to the base level of the
    //doc library and rename it
    SPList tmpList = ParentWeb.Lists[
       rootFolder.ContainingDocumentLibrary];
    blankFolder.MoveTo(_sharePointLibrary + "\\" +
       subFolderName);
    tmpList.Update();
  6. Grant permission to this new folder to the appropriate customer. Keep in mind this will automatically add a “limited access” permission for the customer to the document library’s access control list, because the customer needs access to something at a lower level in the library (the new folder). That’s why you needed the top-level BlankFolder with zero permissions from step 3—it acts as the parent for new folders, ensuring that SharePoint doesn’t have to copy all the limited-access permissions from the top level library, only the permissions from BlankFolder.
  7. Here’s some example code that assigns permissions to a new folder:

    SPRoleAssignment assgn = new SPRoleAssignment(
       groupName, null, groupName, null);
    assgn.RoleDefinitionBindings.Add(roleDef);
    item.RoleAssignments.Add(assgn);
    item.Update();

That should do it! Your users should be able to access the documents without performance issues, and the import process should work at an acceptable speed as well.

As you’ve seen, creating item-level permissions in SharePoint can be tricky, but if you’re careful, they can be an effective tool for meeting business requirements. The trick described in this article is a good one to keep in your back pocket in case you ever need it!

  • Utilize SharePoint @ Home
  • Backup your files free with Live Mesh
  • SharePoint Workflow – Part 1
  • Getting to Know SharePoint
  • Unique ID in InfoPath Using SharePoint
    • Delicious
    • Facebook
    • Digg
    • Reddit
    • StumbleUpon
    • Twitter

    One Response to “Solve Item-Level Permission Performance Problems in SharePoint”

    1. Samarendra Swain 18 March 2010 at 12:45 am (PERMALINK)

      I have requirement like, on my import process I am creating more than one document library dynamically.

      if breaking the Role inheritance of one document library taking around 4-5 min , then I am creating 500 document library dynamically (that ‘s my project requirement ) in one shot, then it’s taking long time to execute my application . Because 500 * 4 = 2000 minutes . Hope you understand the situation.

      Help me..

      Author

    PHVsPjwvdWw+