转:http://blog.csdn.net/ma_jiang/article/details/6553373

部分常见用例场景都是关于显示和编辑SharePoint列表的——可惜,这也是我们看到很多性能问题出现的地方,这是因为SharePoint对象模型并不总是以性能优化的方式被使用。

用例1:在SharePoint列表中,存储了多少项目?

有多种方式来回答这个问题。我曾经看到很多次的一个例子是下面这样:

int noOfItems = SPContext.Current.List.Items.Count;

这句代码告诉我们在列表中数据项的数目,为了得到这个结果不得不从内容数据库中获取列表的所有项目。下面的截图显示了,当上面代码在访问Count属性的时候,对象模型内部的执行过程:

对于小型列表,这不会有问题,查询还是比较迅速。不过当列表增长数倍,或自定义代码从未在实际数据上测试过的话,这将成为一个问题。

对于这种情况,微软为SPList提供了另外一个属性,名为ItemCount。正确的代码应该是:

int noOfItems = SPContext.Current.List.ItemCount;

在这种情况下,SharePoint只用在内容数据库中查询Lists数据表的单个记录。在列表中数据项的数量会被冗余地存储在这,以便无需查询整个AllUserData数据表(所有的SharePoint列表项目都保存在这里)就可获得这个信息。

用例2:使用SPList显示列表中的项目?

通过SharePoint对象模型,有多种方法可以遍历SharePoint列表的数据项。我曾经在一个实际运行的SharePoint应用程序中 见到的这样一个方式——在开发人员机器上或在非常小的列表上可能会工作正常,但是一旦在超过几百条数据项的列表上执行,这种方式就会出现致命的性能问题。 让我们看一下代码片段,它被用于一个WebPart中,从当前上下文的SharePoint列表中获取前100个数据项:

SPList activeList = SPContext.Current.List;

for(int i=0;i<100 && i

SPListItem listItem = activeList.Items[i];

htmlWriter.Write(listItem["Title"]);

}

假定在这个列表中至少有100条数据项——这段代码为了获取前100个SharePoint列表数据项的100个Title值,会往返访问数据库多少次?你也许会很惊讶。经过对上述代码的执行过程的分析,在你看到来着数据库的视图的时候,一共对数据库进行了200次调用:

原因在于,在每次循环中,当访问Items属性的时候,我们都请求了一个新的SPListItemCollection对象。Items属性未被缓存,因此总是从数据库中反复不断地请求所有数据项。下面是第一个循环迭代的情况:

正确的方法

正确的方法当然是把Items属性的返回值存储在一个SPListItemCollection变量中。这样,数据库就只会查询一次,并且我们接下来也可以遍历存储在集合对象里面的结果集。下面是修改后的示例代码:

SPListItemCollection items = SPContext.Current.List.Items;

for(int i=0;i<100 && i

SPListItem listItem = items[i];

htmlWriter.Write(listItem["Title"]);

}

你也能使用foreach循环语句,它会被编译为类似的代码,其充分利用了Items集合的IEnumerable接口。下面是新的循环在内部如何被处理的过程:

用例3:使用SPQuery和SPView只请求你真正需要的数据

在必须处理来自数据库的数据的任何类型应用程序中,我们都能见到的一个主要性能问题是,有太多数据要访问。请求比当前用例所需的数据量更多的信息,会导致额外的:

  • 在数据库上的查询开销,以便收集请求信息
  • 在数据库和应用程序之间的通讯开销
  • 在数据库和应用程序上的内存开销

回头看一下前面2个用例,你会发现被执行的SQL Statement总是从请求的SharePoint列表中选取了所有数据项。你可以说你看到SELECT子句是这样书写:SELECT TOP 2147483648……

限制返回行的数量

在访问SharePoint列表中的数据项的时候,万一你只想得到有限数量的结果集,那么你可以利用SPQuery.RowLimit属性。

下面是一个例子:

SPQuery query = new SPQuery();

query.RowLimit = 100;

SPListItemCollection items = SPContext.Current.List.GetItems(query);

for (int itemIx=0;itemIx

SPListItem listItem = items[itemIx];

}

在SPList.GetItems方法中使用SPQuery对象,将生成包含如下SELECT子句的结果。

在之前的例子中,我们已经限制了想要获取的数据项数目。然而,我们依旧还是请求了定义在SharePoint列表中的所有列。对于真正需要把所有列 都显示给最终用户,或者需要所有列来完成某些计算的情况,这样做毫无问题。然而,在大部分情况下,我们只需要几个而不是全部的列。

限制检索列

有两种方法来限制哪些列要从数据库检索:

  • 使用SharePoint视图:SPView
  • 使用SPQuery.ViewFields属性

因此上面的示例代码可以用如下两种方式进行修改:

SPQuery query = new SPQuery(SPContext.Current.CurrentView.View);

或
SPQuery query = new SPQuery();

query.ViewFields = "";
在两种场景中,SELECT子句都只包含那些定义在SharePoint视图中的字段,这些字段各自在ViewFields属性中被引用:

用例4:通过SPQuery来对SharePoint列表数据项进行分页

SharePoint列表能包含成千上万的数据项。我们都听说,为了获得较好的列表性能,不应该超过2000条的限度 。当超过这个限度后,确实存在性能影响。有一些方法可以克服这个限度,就是使用索引列和视图。

在访问列表中的数据时,除了考虑这些因素外,还有一个方面比较重要。在之前的用例中已经解释过——只访问你需要的数据可以大大降低SharePoint内容数据库 的压力。另外,SharePoint对象模型
也提供了一些额外的特性来加强访问列表数据项的能力。

数据分页就是其中一个技术,就是我们在富客户端应用程序或Web应用程序中已经熟知的,使用数据网格类似的方式。分页让最终用户便捷地导航数据,并且——如果正确地实现的话——可以减少低层数据库的负载。

SPQuery对象提供了属性ListItemCollectionPosition,通过它你能够设定查询页的起始位置。RowLimit让你设定每页要获取多少数据项。让我们来看一些示例代码:


SPQuery query = new SPQuery();

query.RowLimit = 10; // that is our page size

do

{

SPListItemCollection items = SPContext.Current.List.GetItems(query);

// do something with the page result
// set the position cursor for the next iteration query.ListItemCollectionPosition = items.ListItemCollectionPosition; } while (query.ListItemCollectionPosition != null) SPList.GetItems执行了这个查询,每次调用GetItems只返回10条数据项。SPListItemCollection提供的
ListItemCollectionPosition属性就像SharePoint列表上的一个指针。这个属性能用于任何页面遍历,以定义下一页的起始
点。下面的插图显示了数据库的活动:

仔细看一下展现给我们的这个SQL Statement,它混合了SELECT TOP和WHERE子句,用于获取某个页的数据项:

用例5:更新大量的SharePoint列表数据项

之前的用例关注于存储在SharePoint列表中的数据项的读取访问。现在来讨论一下如何更好地更新或添加新数据项了。由于SharePoint对象模型提供了丰富的接口,所以我们又可以在多种方式中进行选择了。

在SharePoint列表中添加和更新数据项的第一个显而易见的方式是,SPListItem.Update。要获得一个列表数据项,既能通过查询一个现存数据项,又可以用SPListItemCollection.Add来添加一个新的。

让我们看一下如下的例子:

for (int itemIx=0;itemIx<100;itemIx++) {

SPListItem newItem = items.Add();

// fill all the individual fields with

valuesnewItem.Update();

}

对这段代码进行分析,我们看到对Update方法的每次调用实际上都调用了内部方法SPListItem.AddOrUpdateItem,它事实上是调用了一个存储过程来完成这个任务:

我们看到,添加100条数据项到我的列表中,花费了4.5秒的时间。

使用批量更新代替单个更新

如果你必须更新大量的数据项,强烈建议你不要在每个数据项上独立使用Update方法。而是,使用SPWeb提供的批量更新函数ProcessBatchData。

ProcessBatchData执行以XML格式定义的批量方法 。这里有一篇很好的文章 解释了如何使用批量更新。通过利用批量更新,可以把上面的例子实现为这样:


StringBuilder query = new StringBuilder();

for (int itemIx=0;itemIx<100;itemIx++) {

query.AppendFormat("" +"{1}" +"New" +"Save" +"{2}" +
"", itemIx, listGuid, someValue, "urn:schemas-microsoft-com:office:office#"); } SPContext.Current.Web.ProcessBatchData("" +"{0}", query.ToString())

通过ProcessBatchData添加同样的100条数据项,通过分析内部机理,我们知道在更新过程中花费了多少时间:

两种更新方式的对比表明,我们可以通过批量更新来获得巨大的性能提升:

注意

批量更新实际上只在执行大量更新的时候才被推荐。不过,请思考一下创建批量更新XML的花销:

  • 确保使用StringBuilder,而不是把一些独立字符串对象连接在一起。
  • 分割批量更新调用,以保持生成的XML足够小,不会出现内存溢出异常。在执行上述包含了50000个批量更新的例子的时候,我就遇到了OOM(内存溢出)。

用例6:哪一个是我最慢的列表,它们如何被使用以及为什么会慢?

我们知道,SharePoint列表性能随着存储在其中的数据项的数量增加而降低,并且也和显示的时候,列表如何进行过滤有关。你可以找到谈及每个列表2000条数据项限度的很多文章和博客帖子

为了做正确的事获得良好的性能,首先需要了解当前的使用情况并分析性能问题。

有几种方式可以算出你的SharePoint应用程序的当前访问统计量。你可以分析IIS日志文件 ,或者使用SharePoint使用率报告特性(SharePoint
Usage Reporting Feature
)。

监测列表性能最简单的方式就是分析各个SharePoint List和SharePoint  View的URL的HTTP响应次数。SharePoint  URL的格式类似这样:http://servername/site/{LISTNAME}/{VIEWNAME}.aspx。

为了分析它,我们可以基于这两个标记来对请求进行分组。我使用dynaTrace的Business Transaction 特性依照正则表达式来分组捕获到的PurePath's

这样的结果让我们明白,哪些列表和视图使用最频繁,它们表现如何。

此外,对HTTP请求进行分析——它只为那些显示特定列表或视图的页面提供准确的数据——这样,我们就能分析自定义Web部件或自定义页面的列表使用率,它们往往比单个列表或视图被访问得更多,也比那些以特定过滤方式来访问列表的情况多。

我们也能分析与SharePoint对象模型交互的情况,比如被用于呈现列表和视图的SPRequest.RenderViewAsHtml的使用情况,对SPList和SPView的访问情况。下面的插图显示了对SPRequest方法调用的使用率和性能指标:

上面的插图给我们展现了,列表的内部GUID。每个列表和视图都通过GUID来唯一标识。这是查找真实列表名称的另外一种方式:你可以吧GUID粘贴进URL中,以编辑列表和视图的设置。下面是一个例子:

http://servername/_layouts/listedit.aspx?List={GUID} (GUID must be URL-Encoded). 

这为我们提供了另外一种打开内容数据库和查询AllLists数据表的方式。这个数据表包含着GUID和List名称。

列表为什么慢?

现在,由于我们已经知道哪些列表和视图被频繁访问,我们就能重点关注那些让性能下降的地方。为了改善最终用户体验,我们应该集中在最频繁访问的列表上,而不是那些偶尔访问一下的列表。

列表表现缓慢,存在有多种原因:

  • 有太多的数据项显示在列表视图中
  • 有太多的数据项保存于没有过滤和索引列的列表中
  • 自定义Web部件进行了无效率的数据访问

Conclusion

SharePoint对象模型提供了一种轻松的灵活的方式来扩展SharePoint应用程序。这个框架提供了不同的机制来访问和编辑存储在  SharePoint列表中的数据。然而,不是每种可能的方式对于每个用例场景都是可取的。了解SharePoint对象模型的内部原理可以让我们创建的  SharePoint应用程序运行得更好,性能更易伸缩。

SharePoint对象模型性能考量的更多相关文章

  1. 【DSP开发】HyperLink 编程和性能考量

    冯华亮/Brighton Feng---Communication Infrastructure 摘要 HyperLink 为两个 KeyStone 架构 DSP 之间提供了一种高速,低延迟,引脚数量 ...

  2. SharePoint服务器端对象模型 之 对象模型概述(Part 1)

    在一个传统的ASP.NET开发过程中,我们往往会把开发分为界面展现层.逻辑业务层和数据访问层这三个层面.作为一个应用开发平台,SharePoint是微软在直观的开发能力和自由的扩展能力之间,取到的一个 ...

  3. SharePoint 服务器端对象模型 之 使用LINQ进行数据访问操作(Part 2)

    (四)使用LINQ进行列表查询 在生成实体类之后,就可以利用LINQ的强大查询能力进行SharePoint列表数据的查询了.在传统SharePoint对象模型编程中,需要首先获取网站对象,再进行其他操 ...

  4. SharePoint服务器端对象模型 之 序言

    对于刚刚开始接触SharePoint的开发人员,即使之前有较为丰富的ASP.NET开发经验,在面对SharePoint时候可能也很难找到入手的方向.对于任何一种开发平台而言,学习开发的过程大致会包括: ...

  5. SharePoint服务器端对象模型 之 对象模型概述(Part 2)

    (三)Url 作为一个B/S体系,在SharePoint的属性.方法参数和返回值中,大量的涉及到了Url,总的来说,涉及到的Url可以分为如下四类: 绝对路径:完整的Url,包含了协议头(http或h ...

  6. SharePoint服务器端对象模型 之 访问网站和列表数据(Part 1)

    本节将会介绍SharePoint中最为常用的一些对象模型,以及如何使用这些对象模型来访问和操作网站中的数据.几乎所有的SharePoint服务器端开发都会涉及到这些内容,因此应着重掌握本节中所介绍的基 ...

  7. SharePoint服务器端对象模型 之 访问网站和列表数据(Part 5)

    (五)列表条目(SPListItem) SharePoint中数据的存储基本上都是通过列表条目来完成(文档库中的文档也是一种特殊的列表条目),因此在SharePoint应用开发中,最终是要和列表条目打 ...

  8. 如何提升SharePoint 2010的性能

    文章来自: http://www.chinaemail.com.cn/server/xtfl/Exchange/201109/66466.html SharePoint是微软历史上销售量增长最快的产品 ...

  9. Sharepoint学习笔记—习题系列--70-576习题解析 -(Q99-Q101)

    Question  99 You have designed a new SharePoint 2010 Web Part that was deployed to the testing envir ...

随机推荐

  1. 【安装操作系统】VMware 中安装 Redhat 5

    引言 已有一台 Windows XP 家用机,安装 Linux 虚拟机,一不小心就会走弯路,因此本文提供一些入门级的经验来帮助你躲开歧途. 欢迎来到 lovickie 的博客 http://www.c ...

  2. 一些浏览器HACKS

    1.选择器HACKS /*IE6及以下*/            *html #uno{...} /*IE7*/                    *:first-child+html #dos{ ...

  3. 恢复Delphi XE2的Library Path

    Delphi XE2好好的,手贱乱删,结果新建一个工程都不能编译了,出现:DELPHI X2 [DCC Fatal Error] KjcxClient.dpr(1): F1027 Unit not f ...

  4. Starting MySQL.. ERROR! The server quit without updating PID file (/usr/local/mysql/data/localhost.localdomain.pid).

      [root@localhost ~]# cd /usr/local/mysql   [root@localhost mysql]# chown -R mysql.mysql . [root@loc ...

  5. Python环境搭建(windows)

    Python环境搭建(windows) Python简介 Python(英国发音:/ˈpaɪθən/ 美国发音:/ˈpaɪθɑːn/),是一种面向对象.直译式计算机编程语言,具有近二十年的发展历史,成 ...

  6. 【BZOJ】1925: [Sdoi2010]地精部落 DP+滚动数组

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1925 题意:输入一个数N(1 <= N <= 4200),问将这些数排列成折线 ...

  7. .net entity framework 泛型 更新与增加记录

    static public bool SaveOrUpdate<T>(T entity) where T: class { bool result = false; using (wech ...

  8. 简易promise

    <!DOCTYPE html><html><head lang="en"> <meta charset="UTF-8" ...

  9. js复制黏贴

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  10. white-space 属性设置如何处理元素内的空白

    定义和用法white-space 属性设置如何处理元素内的空白. 这个属性声明建立布局过程中如何处理元素中的空白符.值 pre-wrap 和 pre-line 是 CSS 2.1 中新增的. 默认值: ...