这里的另一个存储过程在每个页面加载和web服务调用我们的站点时进行调用,因为我们大量使用了Profile provider。
CREATE PROCEDURE [dbo].[aspnet_Profile_GetProperties]
@ApplicationName nvarchar(256),
@UserName nvarchar(256),
@CurrentTimeUtc datetime
AS
BEGIN
DECLARE @ApplicationId uniqueidentifier
SELECT @ApplicationId = NULL
SELECT @ApplicationId = ApplicationId
FROM dbo.aspnet_Applications
WHERE LOWER(@ApplicationName) = LoweredApplicationName
IF (@ApplicationId IS NULL)
RETURN
DECLARE @UserId uniqueidentifier
SELECT @UserId = NULL
SELECT @UserId = UserId
FROM dbo.aspnet_Users
WHERE ApplicationId = @ApplicationId
AND LoweredUserName =
LOWER(@UserName)
IF (@UserId IS NULL)
RETURN
SELECT TOP 1 PropertyNames, PropertyValuesString, PropertyValuesBinary
FROM dbo.aspnet_Profile
WHERE UserId = @UserId
IF (@@ROWCOUNT > 0)
BEGIN
UPDATE dbo.aspnet_Users
SET LastActivityDate=@CurrentTimeUtc
WHERE UserId = @UserId
END
END
@ApplicationName nvarchar(256),
@UserName nvarchar(256),
@CurrentTimeUtc datetime
AS
BEGIN
DECLARE @ApplicationId uniqueidentifier
SELECT @ApplicationId = NULL
SELECT @ApplicationId = ApplicationId
FROM dbo.aspnet_Applications
WHERE LOWER(@ApplicationName) = LoweredApplicationName
IF (@ApplicationId IS NULL)
RETURN
DECLARE @UserId uniqueidentifier
SELECT @UserId = NULL
SELECT @UserId = UserId
FROM dbo.aspnet_Users
WHERE ApplicationId = @ApplicationId
AND LoweredUserName =
LOWER(@UserName)
IF (@UserId IS NULL)
RETURN
SELECT TOP 1 PropertyNames, PropertyValuesString, PropertyValuesBinary
FROM dbo.aspnet_Profile
WHERE UserId = @UserId
IF (@@ROWCOUNT > 0)
BEGIN
UPDATE dbo.aspnet_Users
SET LastActivityDate=@CurrentTimeUtc
WHERE UserId = @UserId
END
END
当运行这个存储过程时,看下面的统计:
Table 'aspnet_Applications'. Scan count 1, logical reads 2, physical reads 0,
read-ahead reads 0, lob logical reads 0, lob physical
reads 0, lob read-ahead reads 0.
(1 row(s) affected)
Table 'aspnet_Users'. Scan count 1, logical reads 4, physical reads 0,
read-ahead reads 0, lob logical reads 0, lob physical
reads 0, lob read-ahead reads 0.
(1 row(s) affected)
(1 row(s) affected)
Table 'aspnet_Profile'. Scan count 0, logical reads 3, physical reads 0,
read-ahead reads 0, lob logical reads 0, lob physical
reads 0, lob read-ahead reads 0.
(1 row(s) affected)
Table 'aspnet_Users'. Scan count 0, logical reads 27, physical reads 0,
read-ahead reads 0, lob logical reads 0, lob physical
reads 0, lob read-ahead reads 0.
(1 row(s) affected)
(1 row(s) affected)
read-ahead reads 0, lob logical reads 0, lob physical
reads 0, lob read-ahead reads 0.
(1 row(s) affected)
Table 'aspnet_Users'. Scan count 1, logical reads 4, physical reads 0,
read-ahead reads 0, lob logical reads 0, lob physical
reads 0, lob read-ahead reads 0.
(1 row(s) affected)
(1 row(s) affected)
Table 'aspnet_Profile'. Scan count 0, logical reads 3, physical reads 0,
read-ahead reads 0, lob logical reads 0, lob physical
reads 0, lob read-ahead reads 0.
(1 row(s) affected)
Table 'aspnet_Users'. Scan count 0, logical reads 27, physical reads 0,
read-ahead reads 0, lob logical reads 0, lob physical
reads 0, lob read-ahead reads 0.
(1 row(s) affected)
(1 row(s) affected)
该存储过程操作绑定了所有客户属性的Profile 对象。在第一次请求过程中,无论什么时候该对象都会被访问。
首先,它会通过SELECT 表aspnet_application根据应用程序的名称找出应用程序的ID。你可以方便的在SP中将应用程序ID进行硬编码来取代这个方法,而且这样做也会节约很多时间。正常情况下,我们仅仅会在我们的产品服务器上运行一个应用程序。因此,不需要为每次单独的调用查找应用程序ID。这是一种快速优化方法。然而,从客户端统计来看,你可以看到真实的性能瓶颈在那里:
然后看看最后一个块,其中 aspnet_users表的LastActivityDate字段被更新了。这是耗费资源最昂贵的一个。
这样做是为了确保Profile provider记住什么时候是用户的profile被最后一次访问。我们不需要在每个单独页面加载以及Web服务调用Profile对象时都这样做。我们可以在用户第一次登录和注销时这么做。这样仅仅只是一个页面而已。因此,我们可以方便地删除它以便节约更多的开销来确保在每个单独Web服务调用时需要更新的大表aspnet_users。