记一个调用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掉一个.

问题就解决了.

你可能感兴趣的:(object)