0

We have a SharePoint 2013 on-premises team site and we have a document library which have around 29,000 +++ items, and those files are structured under around 4,000 folders and sub-folder. now inside our Server-side event receiver, i am using the following method to copy files and folder, as follow:-

private void copyfiles(SPItemEventProperties properties, SPListItem currentItem, string from, string to)
        {
    try
     {
      SPFolder folder = properties.Web.GetFolder(properties.Web.ServerRelativeUrl + "/Shared Documents/" + currentItem["ReferenceNumber"] + "/" + from + "/");
      SPDocumentLibrary currentDL = (SPDocumentLibrary)properties.Web.GetList(properties.Web.ServerRelativeUrl + "/Shared Documents/");
      SPListItem softemplete = null;
      TaxonomyFieldValue taxFieldValue = currentItem["CustomerName"] as TaxonomyFieldValue;

      var label = taxFieldValue.Label;
      var titlewithoutspecialchar = currentItem["Title"].ToString().Replace("~", " ").Replace("\"", " ").Replace("#", " ").Replace("%", " ").Replace("&", " ").Replace("*", " ").Replace(":", " ")
              .Replace("<", " ").Replace(">", " ").Replace("?", " ").Replace("/", " ").Replace("\\", " ").Replace("{", " ").Replace("}", " ").Replace("|", " ").Replace(".", " ");
       if (folder.ItemCount > 0)
          {
            SPList list = properties.Web.GetList(properties.Web.ServerRelativeUrl + "/Shared Documents/");
            SPQuery query = new SPQuery();
            query.Folder = folder;
            SPListItemCollection listitem = list.GetItems(query);
              foreach (SPListItem i in listitem)
               {
                 if ((i.Name.ToLower().Contains(currentItem["ReferenceNumber"].ToString().ToLower() + " -") &&
                    (i.Name.ToLower().Contains("sof") || i.Name.ToLower().Contains("pof") || i.Name.ToLower().Contains("qo"))

                     )
                       ||
                     i.Name.ToLower().Contains("request for approval"))
                   {
                     softemplete = i;
                       if (softemplete != null)
                          {
                            byte[] fileBytes = softemplete.File.OpenBinary();
                            string destUrl = properties.Web.ServerRelativeUrl + "/" + currentDL.RootFolder.Url + "/" +
                             currentItem["ReferenceNumber"] + "/" + to + "/" + currentItem["ReferenceNumber"] + " - " + label + " - " + titlewithoutspecialchar.Trim() + ".xlsx";
                             if (i.Name.ToLower().Contains("request for approval.oft"))
                                {
                                    destUrl = properties.Web.ServerRelativeUrl + "/" + currentDL.RootFolder.Url + "/" +
                                   currentItem["ReferenceNumber"] + "/"+to+"/Request for Approval.oft";
                                }
                              else if (i.Name.ToLower().Contains("request for approval.xlsm"))
                                {
                                    destUrl = properties.Web.ServerRelativeUrl + "/" + currentDL.RootFolder.Url + "/" +
                                   currentItem["ReferenceNumber"] + "/" + to + "/Request for Approval.xlsm";
                                }
                                try
                                {
                                    SPFile destFile = currentDL.RootFolder.Files.Add(destUrl, fileBytes, false);
                                }
                                catch
                                {
                                }
                            }

                        }
                    }
                }
            }
            catch
            {
            }


        }

Now the this method is taking quite long to complete the copy (sometimes around 10 seconds), although i am using CAML query to only search the files inside the desired folder usingquery.Folder = folder;. so can anyone provide any advice about improving this method? as i think it is already tuned to the max, is this correct?

3
  • 1
    does the Shared Documents library has this event receiver or it is called from another list? Jan 12, 2020 at 15:51
  • @MSallal the event receiver is called from another custom list..
    – John John
    Jan 12, 2020 at 23:02
  • Haven't been using SSOM for a long time but what about limiting the row count for the query, getting multiple SPListItemCollections instead of one and parallelizing the copy operation? The reason to get multiple SPListItemCollections is due to the fact that you cannot do like Parallel.Foreach(listItemCollection...).
    – Ciamas
    Jan 17, 2020 at 18:17

2 Answers 2

1

Several things to try:

2
  • thanks a lot for the valuable points. for the last point, i am not fetching all the items, i am defining a CAML query to only get the related folder query.Folder = folder; which in our case will only contain max of 15 folders and documents..so this should not be an issue i think..
    – John John
    Jan 13, 2020 at 22:33
  • Also look at this: docs.microsoft.com/en-us/previous-versions/office/developer/…
    – Mike
    Jan 13, 2020 at 23:52
0

all that was mentioned by Mike are valid tips and should be deferentially checked and considered

other thing I would check which may have a huge performance impact is the way You query items from SharePoint. Using SPQuery and GetItems() method is not the best way. First of all it does not provide any caching and returns SPListItem objects that have all metadata (columns) loaded (which sometimes is not the best option as You for example would like to only use information from 4 or 5 columns)

better option is to use CrossListQueryInfo with cache turned on. The difference is that it will return a DataTable by default. The advantage is possible caching and also it is mandatory to provide the list of fields You plan to be using (and only those will be initialized in the returned list of objects). Example implementation of this kind of query would look like:



    DataTable dt = null;
    CrossListQueryInfo crossListQueryInfo = new CrossListQueryInfo();
    crossListQueryInfo.Query = "<Where><IsNotNull><FieldRef Name='Title'/></IsNotNull></Where>";
    crossListQueryInfo.ViewFields = "<FieldRef Name=\"Title\" />";
    crossListQueryInfo.Lists = "<Lists><List ID='[GIUD OF LIST]'/></Lists>";
    crossListQueryInfo.Webs = "<Webs Scope='Recursive' />";
    crossListQueryInfo.UseCache = true;
    CrossListQueryCache crossListQueryCache = new CrossListQueryCache(crossListQueryInfo);
    dt = crossListQueryCache.GetSiteData(SPContext.Current.Site);
    return dt;


Please refer to this article to check different methods of query and their performance. Check this chart... the CorssListQueryInfo is the blue line at the bottom of the chart :).

Hope this will be of any help :). I know SP may be performance tricky :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.