【问题标题】:Sharepoint 2010 - updating large list , processes very slowly and times outSharepoint 2010 - 更新大型列表,处理非常缓慢并超时
【发布时间】:2014-01-22 12:06:14
【问题描述】:

我有一种情况,我必须根据记录是否有打开或关闭的项目,将源记录列表状态列更新为打开或关闭 - 项目列表可以有多个项目链接到源记录通过项目中源记录的 ID 和客户 ID,代码是检索客户项目,然后检查是否有结束日期,如果没有 - 它打开 - 如果有 - 它关闭。这些共享点列表很大

我编写的代码基本上允许我指定一个开始 ID,然后当我单击运行按钮时它会在停止之前处理这么多记录 - 我把它放在适当的位置,因为这个过程非常缓慢,甚至超时,但我不明白为什么它这么慢而且这么好..不稳定 - 如果我尝试处理超过 150 条记录 - 它会超时,服务器本身是一个带有 24gb 内存的八核系统,所以我不认为它是服务器,这可能是我的代码。

    protected void Button1_Click(object sender, EventArgs e)
    {
        SPWeb web = SPControl.GetContextWeb(this.Context);
        string SPsiteUrl = SPContext.Current.Web.Url;
        Label1.Text = "Running";
        int start;
        start = Convert.ToInt32(TextBox1.Text);
        start = int.Parse(TextBox1.Text);
        int end = start + 150;
        int count = 0;

        using (SPSite oSite = new SPSite(SPsiteUrl))
        {
            using (SPWeb oWeb = oSite.OpenWeb("/Client"))
            {
                // get lists
                SPList oList = oWeb.Lists["Source Records"];
                SPList pList = oWeb.Lists["Project"];

                // query Source Records 
                string sQuery = @"<Where><And><Geq><FieldRef Name='ID' /><Value Type='Number'>" + start + "</Value></Geq><Leq><FieldRef Name='ID'/><Value Type='Number'> "+ end +"</Value></Leq></And></Where>";
                string sViewFields = @"<FieldRef Name='ID' />";
                string sViewAttrs = @"Scope=""Recursive""";
                uint iRowLimit = 0;

                var oQuery = new SPQuery();
                oQuery.Query = sQuery;
                oQuery.ViewFields = sViewFields;
                oQuery.ViewAttributes = sViewAttrs;
                oQuery.RowLimit = iRowLimit;

                SPListItemCollection collListItems = oList.GetItems(oQuery);

                // for each item

                foreach (SPListItem oListItem in collListItems)
                {
                    // get the client id 

                    int id = oListItem.ID;

                        count = count + 1; 
                        //Label1.Text = "Checking record" + id;
                        bool isopen = false;
                        // for each client id access the projects list
                        // query the closed date
                        string Query = @"<Where><Eq><FieldRef Name=""Client_x003a_ID"" /><Value Type=""Text"">" + id + "</Value></Eq></Where>";
                        string pViewFields = @"<FieldRef Name=""End_x0020_Date"" />";
                        string pViewAttrs = @"Scope=""Recursive""";
                        uint pRowLimit = 0;
                        var pQuery = new SPQuery();
                        pQuery.Query = Query;
                        pQuery.ViewFields = pViewFields;
                        pQuery.ViewAttributes = pViewAttrs;
                        pQuery.RowLimit = pRowLimit;
                        SPListItemCollection ListItems = pList.GetItems(pQuery);

                        foreach (SPListItem ListItem in ListItems)
                        {
                            try
                            {
                                DateTime enddate = (DateTime)ListItem["End_x0020_Date"];
                                if (enddate != null)
                                {
                                    isopen = false;
                                }
                                // else if the date is null set the open to true
                                else
                                {
                                    isopen = true;
                                }
                            }
                            catch
                            {
                                string enddate = null;
                                if (enddate == null)
                                {
                                    // if the end date is present set project closed to true
                                    isopen = true;
                                }
                            }

                        // if project is open
                        if (isopen)
                        {
                            oWeb.AllowUnsafeUpdates = true;
                            SPListItem itemupdate = oWeb.Lists["Source Records"].Items.GetItemById(id);
                            itemupdate["Status"] = "Open";
                            itemupdate.Update();
                            oWeb.AllowUnsafeUpdates = false;
                            // set records on source record to open
                        }
                        //else // project is closed
                        //{
                        //    oWeb.AllowUnsafeUpdates = true;
                        //    SPListItem itemupdate = oWeb.Lists["Source Records"].Items.GetItemById(id);
                        //    itemupdate["Status"] = "Closed";
                        //    itemupdate.Update();
                        //    oWeb.AllowUnsafeUpdates = false;
                        //    // set the record to closed 
                        //}
                    }
                }
                Label1.Text = "Finished Number of records checked: " + count + " of " + collListItems.Count;
            }
        }
    }'

【问题讨论】:

  • 代码是从 wsp 中提取的编码文件 - 已编辑以包含整个代码,包括注释掉的代码

标签: c# sharepoint sharepoint-2010


【解决方案1】:

而不是

SPListItem itemupdate = oWeb.Lists["Source Records"].Items.GetItemById(id);

试试这个:

SPListItem itemupdate = oWeb.Lists["Source Records"].GetItemById(id);

【讨论】:

  • 他的问题是他在循环中执行复杂而昂贵的查询,而这正是他的主要成本所在。这种变化根本不会产生太大影响。
  • 对不起,我强烈反对这里。 SPList.Items 是一项非常昂贵的操作。本质上,它将从列表中检索所有项目。它正在循环中发生。所以。如果“源记录”列表中有 1000-2000 个项目,则考虑“foreach (SPListItem oListItem in collListItems)”将花费大量时间。总的来说,这段代码有几个严重的问题,而不仅仅是一个。例如,SPWeb.Lists[""] 也是非常昂贵的操作,您应该从循环中移出等
  • 但这只是有条件的。这是一个的问题,但这并不能改变这个算法的核心设计存在缺陷的事实。他不应该在双重嵌套循环中按 ID 获取项目根本,此外他甚至不应该一个双重嵌套循环,其中每个循环代表一个数据库查询。所以虽然这确实解决了一些问题,但当你完成后它仍然会留下一个损坏的解决方案。
【解决方案2】:

您需要更新嵌套循环的代码。而不是这个:

foreach (SPListItem item1 in sPList.GetItems(sPQuery1))

尝试使用这个:

SPListItemCollection items1 = sPList.GetItems(sPQuery1);
foreach (SPListItem item1 in items1)

详情请参考此blog post

更新:您必须尝试摆脱嵌套循环。我认为您可以通过将源列表中的引用添加到项目列表中来实现这一点,并参考那里的End Date 列。

【讨论】:

  • 您建议的更改不会改变任何事情。 foreach 循环只评估一次IEnumerable 对象,而不是在循环的每次迭代中。这与您链接到的博客文章完全不同。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-11
  • 2013-04-07
相关资源
最近更新 更多