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

问题就解决了.

posted on 2010-09-07 17:05  中道学友  阅读(393)  评论(0编辑  收藏  举报

导航

技术追求准确,态度积极向上