记一个调用Proc_GetObject的古怪问题
有个朋友问过这么一个问题, 说访问站点页面有点慢. 经过排查, 发现问题出在SQL上.
抓了Profiler Trace, 发现ConfigDB里有很多的对存储过程dbo.Proc_GetObject的调用. 进一步排查发现, 每调用一个页面, 都会有几千个这样的调用, 连settings.aspx也是如此.
陈列一些事实如下:
SharePoint每次加载一个页面, 都要去确保一下当前站点上所有的Feature都已经被加载. SharePoint会先得到这个站点上所有feature的guid, 然后先去本地的cache里去捞取这些对象(存储在很多xml文件中).
Windows Server 2003中, 本地cache的位置在:
Drive:\Documents and Settings\All Users\Application Data\Microsoft\SharePoint\Config\GUID
Windows Server 2008中, 本地cache的位置在:
Drive:\ProgramData\Microsoft\SharePoint\Config\GUID
如果某些对象在本地的cache里找不到, 那么就会到ConfigDB里去捞取.
使用下面的语句来搜索某个GUID
SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO Declare @SearchStr uniqueidentifier Set @SearchStr = 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX' BEGIN CREATE TABLE #Results (ColumnName nvarchar(370), ColumnValue nvarchar(3630)) SET NOCOUNT ON DECLARE @TableName nvarchar(256), @ColumnName nvarchar(128), @SearchStr2 nvarchar(110) SET @TableName = '' SET @SearchStr2 = @SearchStr WHILE @TableName IS NOT NULL BEGIN SET @ColumnName = '' SET @TableName = ( SELECT MIN(QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME)) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) > @TableName AND OBJECTPROPERTY( OBJECT_ID( QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) ), 'IsMSShipped' ) = 0 ) WHILE (@TableName IS NOT NULL) AND (@ColumnName IS NOT NULL) BEGIN SET @ColumnName = ( SELECT MIN(QUOTENAME(COLUMN_NAME)) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = PARSENAME(@TableName, 2) AND TABLE_NAME = PARSENAME(@TableName, 1) AND DATA_TYPE IN ('uniqueidentifier') AND QUOTENAME(COLUMN_NAME) > @ColumnName ) IF @ColumnName IS NOT NULL BEGIN INSERT INTO #Results EXEC ( 'SELECT ''' + @TableName + '.' + @ColumnName + ''', LEFT(' + @ColumnName + ', 3630) FROM ' + @TableName + ' (NOLOCK) ' + ' WHERE ' + @ColumnName + ' LIKE ' + '''' + @SearchStr2 + '''' ) END END END SELECT ColumnName, ColumnValue FROM #Results Drop Table #Results END
把Profiler Trace中的GUID拿到ConfigDB里一搜, 没有任何结果.
把该GUID拿到ContentDB里一搜, 发现这个GUID存在于Features表上.
至此, 问题就比较清楚了.
在这套环境中, 有很多的Feature只存在于ContentDB里, 但是在ConfigDB里却不存在. 所以就造成很多feature称为orphan.
加载页面的时候, SharePoint试图加载这些feature, 但是在本地cache里捞不到, 于是就去ConfigDB里通过调用Proc_GetObject找, 也没找到. 由于这些feature并不十分重要, 所以页面也还是正常的加载起来了. 但是, 以后每次加载任何页面都会有这么多的Proc_GetObject调用出现, 由于这样的feature实在是太多了, 所以就影响了performance.
解决方案
==============
移除掉这些orphan的feature就可以了.
怎么移除呢?
欧洲有个巨牛的牛人叫做Stefan, 他公开了两个命令行的工具, 一个可以扫描feature, 另一个可以移除feature. 链接如下:
http://code.msdn.microsoft.com/WssAnalyzeFeatures/Release/ProjectReleases.aspx?ReleaseId=886
http://code.msdn.microsoft.com/WssRemoveFeatureFrom/Release/ProjectReleases.aspx?ReleaseId=887
合并这两个工具中的逻辑, 每发现一个orphan的feature, 就delete掉一个.
问题就解决了.