我有一个存储过程,大约需要15秒才能执行。当数百个请求进入时,我们看到了不可接受的页面加载时间。有时两分钟。该页面根据ID加载结果,因此每个人的结果都不一样。
我的解决方案是使用临时表,只有在页面没有加载5分钟时才更新它。我认为这会减少该存储过程的负载。但现在我发现了这个临时表的问题。
如果页面没有被点击5分钟,则根据ID从登台表中删除,然后运行存储过程并将结果插入登台表。
然后使用"总结果计数"更新登台表,根据ID从登台表中选择
您可以看到它正在执行DELETE,INSERT,UPDATE和SELECT。在负载下,我遇到了大量的死锁。
几个问题:
代码:
CREATE procedure [dbo].[BB02_ListFundraisersForEvent] (
@DesignEventId int,
@Offset int,
@PageSize int,
@SearchTerms varchar(100) = null,
@OrderByField varchar(25) = 'DEFAULT',
@OrderByDirection varchar(5) = 'ASC'
)
-- exec BB02_ListFundraisersForEvent 38639, 0, 10, '', '', 'ASC', null
as
set transaction isolation level read uncommitted
declare @UpdateIncrement DateTime = DATEADD(MINUTE, -5, GETDATE());
declare @FundraiserCount int;
declare @LastUpdated DateTime;
declare @PAGE_STATUS_CANCELED int;
declare @TOTAL_TYPE_NON_REJECTED int;
declare @TOTAL_TYPE_REGISTRATION int;
declare @PROFILE_APPEAL_WEB_DIR_FAMILY int;
declare @PROFILE_LEVEL_WEB_DIR_FAMILY int;
set @TOTAL_TYPE_NON_REJECTED = 2;
set @TOTAL_TYPE_REGISTRATION = 3;
set @PAGE_STATUS_CANCELED = 3
set @PROFILE_APPEAL_WEB_DIR_FAMILY = 3;
set @PROFILE_LEVEL_WEB_DIR_FAMILY = 2;
if @OrderByField not in ('FirstName', 'LastName', 'TotalRaised') set @OrderByField = 'DEFAULT';
IF isnull(@SearchTerms, '') = ''
BEGIN
select @FundraiserCount = (select count(*) from bb02_olr_getsupporterscache where designeventid = @DesignEventId)
select @LastUpdated = (select top 1 lastupdated from bb02_olr_getsupporterscache where designeventid = @DesignEventId)
IF( (@FundraiserCount = 0) OR (@LastUpdated < @UpdateIncrement ) OR (ISNULL(@LastUpdated, '') = '') )
BEGIN
DELETE FROM BB02_OLR_GetSupportersCache
WHERE designeventid = @DesignEventId
INSERT INTO bb02_olr_getsupporterscache (DesignEventId,
AppealName,
AppealWebDirectory,
FirstName,
ImageChoice,
LastName,
PhotoURL,
ProfileWebDirectory,
TotalRaisedOffline,
TotalRaisedOnline,
TotalContributions,
DisplayPhoto,
HasStockImages,
LastUpdated)
SELECT
DesignEventId,
AppealName,
AppealWebDirectory,
FirstName,
ImageChoice,
LastName,
PhotoURL,
ProfileWebDirectory,
TotalRaisedOffline,
TotalRaisedOnline,
TotalContributions,
DisplayPhoto,
HasStockImages,
getdate() as LastUpdated
FROM (
-- fundraising pages
SELECT
de.DesignEventId,
egg.EventGivingGroupName as AppealName,
awd.WebDirectoryName as AppealWebDirectory,
c.FirstName,
egg.ImageChoice,
c.LastName,
egg.PhotoUrl,
cwd.WebDirectoryName as ProfileWebDirectory,
eggt.TotalRaisedOffline,
eggt.TotalRaisedOnline,
eggt.TotalContributions,
CAST(egg.DisplayPhoto AS bit) AS DisplayPhoto,
CAST(CASE WHEN ISNULL(dei.DesignEventId, 0) != 0 then 1 else 0 end as bit) as HasStockImages
FROM
BB02_Event e
INNER JOIN
BB02_EventFundraiserRevenueStream efrs on e.EventId = efrs.EventId
INNER JOIN
BB02_EventGivingGroup egg on efrs.EventFundraiserRevenueStreamId = egg.EventFundraiserRevenueStreamId
INNER JOIN
BB02_EventGivingGroupTotal eggt on egg.EventGivingGroupId = eggt.EventGivingGroupId
INNER JOIN
BB02_Consumer c on c.ConsumerId = egg.ConsumerId
INNER JOIN
BB02_WebDirectory cwd on cwd.WebDirectoryId = c.DefaultWebDirectoryId and cwd.WebDirectoryFamilyId = @PROFILE_LEVEL_WEB_DIR_FAMILY
INNER JOIN
BB02_WebDirectory awd on awd.EventGivingGroupId = egg.EventGivingGroupId and awd.WebDirectoryFamilyId = @PROFILE_APPEAL_WEB_DIR_FAMILY
inner join BB02_DesignEvent de on e.EventId = de.EventId and egg.DesignId = de.DesignId
left join (select distinct DesignEventId from BB02_DesignEventImage) dei on de.DesignEventId = dei.DesignEventId
where eggt.EventGivingGroupTotalTypeId =
case when de.AddFeesToTotal = 1 then @TOTAL_TYPE_REGISTRATION -- 3 includes registration fees
else @TOTAL_TYPE_NON_REJECTED /* 1 = Confirmed, 2 = Not Rejected */
end
and egg.Status <> @PAGE_STATUS_CANCELED
and de.DesignEventId = @DesignEventId
and egg.IsDeleted = 0
union all
-- registrants without pages
select
cer.DesignEventId,
'' as AppealName,
'' as AppealWebDirectory,
FirstName,
'' as ImageChoice,
LastName,
'' as PhotoURL,
'' as ProfileWebDirectory,
0 as TotalRaisedOffline,
0 as TotalRaisedOnline,
0 as TotalContributions,
'' as DisplayPhoto,
cast(case when isnull(dei.DesignEventId, 0) != 0 then 1 else 0 end as bit) as HasStockImages
from BB02_ConsumerEventRegistration cer
left join (select distinct DesignEventId from BB02_DesignEventImage) dei on cer.DesignEventId = dei.DesignEventId
where cer.DesignEventId = @DesignEventId
and cer.ConsumerId not in (
select egg.ConsumerId
from BB02_EventGivingGroup egg
inner join BB02_EventFundraiserRevenueStream efrs on efrs.EventFundraiserRevenueStreamId = egg.EventFundraiserRevenueStreamId
inner join BB02_DesignEvent de on efrs.EventId = de.EventId and egg.DesignId = de.DesignId
where de.DesignEventId = @DesignEventId
)
) a
UPDATE bb02_olr_getsupporterscache
SET TotalCount = (select count(*) from bb02_olr_getsupporterscache where DesignEventId = @DesignEventId)
WHERE DesignEventId = @DesignEventId
END
SELECT * FROM (
select
TotalCount,
SupporterId,
AppealName,
AppealWebDirectory,
FirstName,
ImageChoice,
LastName,
PhotoURL,
ProfileWebDirectory,
TotalRaisedOffline,
TotalRaisedOnline,
TotalContributions,
DisplayPhoto,
HasStockImages,
row_number() over (order by
case when @OrderByField = 'FirstName' and @OrderByDirection = 'ASC' then FirstName end asc,
case when @OrderByField = 'FirstName' and @OrderByDirection = 'DESC' then FirstName end desc,
case when @OrderByField = 'LastName' and @OrderByDirection = 'ASC' then LastName end asc,
case when @OrderByField = 'LastName' and @OrderByDirection = 'DESC' then LastName end desc,
case when @OrderByField = 'TotalRaised' and @OrderByDirection = 'ASC' then (TotalRaisedOnline + TotalRaisedOffline) end asc,
case when @OrderByField = 'TotalRaised' and @OrderByDirection = 'DESC' then (TotalRaisedOnline + TotalRaisedOffline) end desc,
case when @OrderByField = 'DEFAULT' and @OrderByDirection = 'ASC' then AppealName end asc,
case when @OrderByField = 'DEFAULT' and @OrderByDirection = 'DESC' then AppealName end desc
) as rownumber
from (
select * from bb02_olr_getsupporterscache where designeventid = @DesignEventId
) a
) q
where q.rownumber > @Offset
and q.rownumber <= @Offset + @PageSize
order by rownumber;
END
IF isnull(@SearchTerms, '') != ''
BEGIN
declare getSearchStringSegments cursor for
select * from dbo.Split(' ', @SearchTerms)
declare
@segmentId int,
@segment varchar(100),
@segment1 varchar(100),
@segment2 varchar(100),
@segment3 varchar(100)
open getSearchStringSegments
fetch next from getSearchStringSegments into @segmentId, @segment
while @@fetch_status = 0 and @segmentId <= 3
begin
print 1;
if @segmentId = 1 set @segment1 = @segment;
if @segmentId = 2 set @segment2 = @segment;
if @segmentId = 3 set @segment3 = @segment;
fetch next from getSearchStringSegments into @segmentId, @segment
end
close getSearchStringSegments;
deallocate getSearchStringSegments;
select @FundraiserCount = (
-- fundraising pages
select count(egg.EventGivingGroupId)
from BB02_Event e
inner join BB02_EventFundraiserRevenueStream efrs on e.EventId = efrs.EventId
inner join BB02_EventGivingGroup egg on efrs.EventFundraiserRevenueStreamId = egg.EventFundraiserRevenueStreamId
inner join BB02_EventGivingGroupTotal eggt on egg.EventGivingGroupId = eggt.EventGivingGroupId
inner join BB02_Consumer c on c.ConsumerId = egg.ConsumerId
inner join BB02_WebDirectory cwd on cwd.WebDirectoryId = c.DefaultWebDirectoryId and cwd.WebDirectoryFamilyId = @PROFILE_LEVEL_WEB_DIR_FAMILY
inner join BB02_WebDirectory awd on awd.EventGivingGroupId = egg.EventGivingGroupId and awd.WebDirectoryFamilyId = @PROFILE_APPEAL_WEB_DIR_FAMILY
inner join BB02_DesignEvent de on e.EventId = de.EventId and egg.DesignId = de.DesignId
where eggt.EventGivingGroupTotalTypeId =
case when de.AddFeesToTotal = 1 then @TOTAL_TYPE_REGISTRATION -- 3 includes registration fees
else @TOTAL_TYPE_NON_REJECTED /* 1 = Confirmed, 2 = Not Rejected */
end
and egg.Status <> @PAGE_STATUS_CANCELED
and de.DesignEventId = @DesignEventId
and egg.IsDeleted = 0
and (
(egg.EventGivingGroupName like '%'+@segment1+'%' or egg.EventGivingGroupName like '%'+@segment2+'%' or egg.EventGivingGroupName like '%'+@segment3+'%')
or (egg.Attribution like '%'+@segment1+'%' or egg.Attribution like '%'+@segment2+'%' or egg.Attribution like '%'+@segment3+'%')
or (c.FirstName like '%'+@segment1+'%' or c.FirstName like '%'+@segment2+'%' or c.FirstName like '%'+@segment3+'%')
or (c.LastName like '%'+@segment1+'%' or c.LastName like '%'+@segment2+'%' or c.LastName like '%'+@segment3+'%')
)
) + (
-- registrants without pages
select count(cer.ConsumerEventRegistrationId)
from BB02_ConsumerEventRegistration cer
where cer.DesignEventId = @DesignEventId
and cer.ConsumerId not in (
select egg.ConsumerId
from BB02_EventGivingGroup egg
inner join BB02_EventFundraiserRevenueStream efrs on efrs.EventFundraiserRevenueStreamId = egg.EventFundraiserRevenueStreamId
inner join BB02_DesignEvent de on efrs.EventId = de.EventId and egg.DesignId = de.DesignId
where de.DesignEventId = @DesignEventId
)
and (
(cer.FirstName like '%'+@segment1+'%' or cer.FirstName like '%'+@segment2+'%' or cer.FirstName like '%'+@segment3+'%')
or (cer.LastName like '%'+@segment1+'%' or cer.LastName like '%'+@segment2+'%' or cer.LastName like '%'+@segment3+'%')
)
and cer.IsDeleted <> 1
)
select * from (
select
@FundraiserCount as TotalCount,
0 as SupporterId,
AppealName,
AppealWebDirectory,
FirstName,
ImageChoice,
LastName,
PhotoURL,
ProfileWebDirectory,
TotalRaisedOffline,
TotalRaisedOnline,
TotalContributions,
DisplayPhoto,
HasStockImages,
row_number() over (order by
case when @OrderByField = 'FirstName' and @OrderByDirection = 'ASC' then FirstName end asc,
case when @OrderByField = 'FirstName' and @OrderByDirection = 'DESC' then FirstName end desc,
case when @OrderByField = 'LastName' and @OrderByDirection = 'ASC' then LastName end asc,
case when @OrderByField = 'LastName' and @OrderByDirection = 'DESC' then LastName end desc,
case when @OrderByField = 'TotalRaised' and @OrderByDirection = 'ASC' then (TotalRaisedOnline + TotalRaisedOffline) end asc,
case when @OrderByField = 'TotalRaised' and @OrderByDirection = 'DESC' then (TotalRaisedOnline + TotalRaisedOffline) end desc,
case when @OrderByField = 'DEFAULT' and @OrderByDirection = 'ASC' then AppealName end asc,
case when @OrderByField = 'DEFAULT' and @OrderByDirection = 'DESC' then AppealName end desc
) as rownumber
from (
-- fundraising pages
select
egg.EventGivingGroupName as AppealName,
awd.WebDirectoryName as AppealWebDirectory,
c.FirstName,
egg.ImageChoice,
c.LastName,
egg.PhotoUrl,
cwd.WebDirectoryName as ProfileWebDirectory,
eggt.TotalRaisedOffline,
eggt.TotalRaisedOnline,
eggt.TotalContributions,
cast(egg.DisplayPhoto as bit) as DisplayPhoto,
cast(case when isnull(dei.DesignEventId, 0) != 0 then 1 else 0 end as bit) as HasStockImages,
row_number() over (order by
case when @OrderByField = 'FirstName' and @OrderByDirection = 'ASC' then c.FirstName end asc,
case when @OrderByField = 'FirstName' and @OrderByDirection = 'DESC' then c.FirstName end desc,
case when @OrderByField = 'LastName' and @OrderByDirection = 'ASC' then c.LastName end asc,
case when @OrderByField = 'LastName' and @OrderByDirection = 'DESC' then c.LastName end desc,
case when @OrderByField = 'TotalRaised' and @OrderByDirection = 'ASC' then (eggt.TotalRaisedOnline + eggt.TotalRaisedOffline) end asc,
case when @OrderByField = 'TotalRaised' and @OrderByDirection = 'DESC' then (eggt.TotalRaisedOnline + eggt.TotalRaisedOffline) end desc,
case when @OrderByField = 'DEFAULT' and @OrderByDirection = 'ASC' then egg.EventGivingGroupName end asc,
case when @OrderByField = 'DEFAULT' and @OrderByDirection = 'DESC' then egg.EventGivingGroupName end desc
) as rownumber
from BB02_Event e
inner join BB02_EventFundraiserRevenueStream efrs on e.EventId = efrs.EventId
inner join BB02_EventGivingGroup egg on efrs.EventFundraiserRevenueStreamId = egg.EventFundraiserRevenueStreamId
inner join BB02_EventGivingGroupTotal eggt on egg.EventGivingGroupId = eggt.EventGivingGroupId
inner join BB02_Consumer c on c.ConsumerId = egg.ConsumerId
inner join BB02_WebDirectory cwd on cwd.WebDirectoryId = c.DefaultWebDirectoryId and cwd.WebDirectoryFamilyId = @PROFILE_LEVEL_WEB_DIR_FAMILY
inner join BB02_WebDirectory awd on awd.EventGivingGroupId = egg.EventGivingGroupId and awd.WebDirectoryFamilyId = @PROFILE_APPEAL_WEB_DIR_FAMILY
inner join BB02_DesignEvent de on e.EventId = de.EventId and egg.DesignId = de.DesignId
left join (select distinct DesignEventId from BB02_DesignEventImage) dei on de.DesignEventId = dei.DesignEventId
where eggt.EventGivingGroupTotalTypeId =
case when de.AddFeesToTotal = 1 then @TOTAL_TYPE_REGISTRATION -- 3 includes registration fees
else @TOTAL_TYPE_NON_REJECTED /* 1 = Confirmed, 2 = Not Rejected */
end
and egg.Status <> @PAGE_STATUS_CANCELED
and de.DesignEventId = @DesignEventId
and egg.IsDeleted = 0
and (
(egg.EventGivingGroupName like '%'+@segment1+'%' or egg.EventGivingGroupName like '%'+@segment2+'%' or egg.EventGivingGroupName like '%'+@segment3+'%')
or (egg.Attribution like '%'+@segment1+'%' or egg.Attribution like '%'+@segment2+'%' or egg.Attribution like '%'+@segment3+'%')
or (c.FirstName like '%'+@segment1+'%' or c.FirstName like '%'+@segment2+'%' or c.FirstName like '%'+@segment3+'%')
or (c.LastName like '%'+@segment1+'%' or c.LastName like '%'+@segment2+'%' or c.LastName like '%'+@segment3+'%')
)
union all
-- registrants without pages
select
'' as AppealName,
'' as AppealWebDirectory,
FirstName,
'' as ImageChoice,
LastName,
'' as PhotoURL,
'' as ProfileWebDirectory,
0 as TotalRaisedOffline,
0 as TotalRaisedOnline,
0 as TotalContributions,
'' as DisplayPhoto,
cast(case when isnull(dei.DesignEventId, 0) != 0 then 1 else 0 end as bit) as HasStockImages,
row_number() over (order by
case when @OrderByField = 'FirstName' and @OrderByDirection = 'ASC' then cer.FirstName end asc,
case when @OrderByField = 'FirstName' and @OrderByDirection = 'DESC' then cer.FirstName end desc,
case when @OrderByField = 'LastName' and @OrderByDirection = 'ASC' then cer.LastName end asc,
case when @OrderByField = 'LastName' and @OrderByDirection = 'DESC' then cer.LastName end desc,
case when @OrderByField = 'TotalRaised' and @OrderByDirection = 'ASC' then (0) end asc,
case when @OrderByField = 'TotalRaised' and @OrderByDirection = 'DESC' then (0) end desc,
case when @OrderByField = 'DEFAULT' and @OrderByDirection = 'ASC' then '' end asc,
case when @OrderByField = 'DEFAULT' and @OrderByDirection = 'DESC' then '' end desc
) as rownumber
from BB02_ConsumerEventRegistration cer
left join (select distinct DesignEventId from BB02_DesignEventImage) dei on cer.DesignEventId = dei.DesignEventId
where cer.DesignEventId = @DesignEventId
and cer.ConsumerId not in (
select egg.ConsumerId
from BB02_EventGivingGroup egg
inner join BB02_EventFundraiserRevenueStream efrs on efrs.EventFundraiserRevenueStreamId = egg.EventFundraiserRevenueStreamId
inner join BB02_DesignEvent de on efrs.EventId = de.EventId and egg.DesignId = de.DesignId
where de.DesignEventId = @DesignEventId
)
and (
(cer.FirstName like '%'+@segment1+'%' or cer.FirstName like '%'+@segment2+'%' or cer.FirstName like '%'+@segment3+'%')
or (cer.LastName like '%'+@segment1+'%' or cer.LastName like '%'+@segment2+'%' or cer.LastName like '%'+@segment3+'%')
)
) a
) q
where q.rownumber > @Offset
and q.rownumber <= @Offset + @PageSize
order by rownumber;
END
答案 0 :(得分:0)
根据获取实际数据所需的时间,缓存数据的想法可能确实值得;问题是在网络服务器层而不是在数据库层中,这样做会有多远。
那就是说,既然你已经掌握了这一部分,那就让我们看一下存储过程。
首先是一些一般性评论:
READ UNCOMMITTED
。我知道你添加了这个以避免锁定,但脏读的想法确实让我感到紧张。您可能会像这样向调用者返回减半或错误的信息。就个人而言,我宁愿等待更长时间才能获得有关信息的信息,而不是获取不良信息。SELECT COUNT(*) ...
来确定是否有任何记录。服务器需要扫描所有相关记录才能获得数字,但您真正感兴趣的是它是否存在。请使用WHERE EXISTS()
。SELECT TOP 1
,那就用它的结果吧。如果找到了值,那么必须有记录!ISNULL(@LastUpdated, '') = ''
字段/变量时,datetime
有点可疑。而是使用@LastUpdated IS NULL
进行此项检查DELETE
后跟可能是重 INSERT
的内容。我想这需要一段时间,这就是死锁的来源。正确的锁定应该有帮助,但我不知道它如何与上面的READ UNCOMMITTED
合作。INSERT
之后,您再次查看新插入的数据,以确定有多少行。由于这里唯一相关的行是我们刚插入的那些,我们可以安全地假设@@ ROWCOUNT已经得到了答案。读取该系统变量不需要花费精力。对SELECT COUNT(*) ...
进行操作会对系统造成更大的负担INSERT
分成两部分,并使用临时表来保存中间结果。我不确定它会在性能方面做出多大的改变(理论上它对服务器来说更多的工作)但我认为它会减少惊喜,特别是如果你把一些统计数据更新。只有测试才能真正说明。无论如何,至于锁定。您获得死锁的原因是您在同一记录上进行了大量操作,并且可能同时从不同的连接进行。因此,一个连接可能正在执行INSERT
而另一个连接尝试执行DELETE
或UPDATE
等等。这可能不会很好。
为了避免这种情况,我会选择锁定,但即使在那里我也可能会遇到问题,因此我会尝试使用“暂停”的应用程序锁定。任何连接,而另一个连接仍在刷新缓存表中的数据。更重要的是,我们可以限制&#39;这会锁定到正在处理的@EventId
。
快点做一些&amp;我在下面提出的代码的脏更改。可能会出现一些语法错误,甚至可能出现一些逻辑错误,因此您可能需要根据需要进行调整/修复。但我希望它会指出你正确的方向。
CREATE procedure [dbo].[BB02_ListFundraisersForEvent] (
@DesignEventId int,
@Offset int,
@PageSize int,
@SearchTerms varchar(100) = null,
@OrderByField varchar(25) = 'DEFAULT',
@OrderByDirection varchar(5) = 'ASC'
)
-- exec BB02_ListFundraisersForEvent 38639, 0, 10, '', '', 'ASC', null
as
-- set transaction isolation level read uncommitted
declare @UpdateIncrement DateTime = DATEADD(MINUTE, -5, GETDATE());
declare @FundraiserCount int;
declare @LastUpdated DateTime;
declare @PAGE_STATUS_CANCELED int;
declare @TOTAL_TYPE_NON_REJECTED int;
declare @TOTAL_TYPE_REGISTRATION int;
declare @PROFILE_APPEAL_WEB_DIR_FAMILY int;
declare @PROFILE_LEVEL_WEB_DIR_FAMILY int;
declare @TotalCount int
declare @cache_was_updated bit
declare @sql nvarchar(max)
declare @rc int
declare @LockName sysname
set @TOTAL_TYPE_NON_REJECTED = 2;
set @TOTAL_TYPE_REGISTRATION = 3;
set @PAGE_STATUS_CANCELED = 3
set @PROFILE_APPEAL_WEB_DIR_FAMILY = 3;
set @PROFILE_LEVEL_WEB_DIR_FAMILY = 2;
if @OrderByField not in ('FirstName', 'LastName', 'TotalRaised') set @OrderByField = 'DEFAULT';
IF @OrderByDirection not in ('ASC', 'DESC') set @OrderByDirection = 'ASC';
SET @cache_was_updated = 0
IF isnull(@SearchTerms, '') = ''
BEGIN
select @LastUpdated = NULL
select TOP 1 @LastUpdated = lastupdated from bb02_olr_getsupporterscache where designeventid = @DesignEventId
IF( (@LastUpdated IS NULL) -- no value found means no data present for given @DesignEventId
OR (@LastUpdated < @UpdateIncrement ) ) -- or value found, but too far in the past)
BEGIN
-- prepare new batch
set @LockName = 'CacheUpdate' + Convert(nvarchar(100), @DesignEventId)
-- get exclusive applock on this @DesignEventId
-- => we should be the only ones that can update this!
EXEC @rc = sp_getapplock @Resource = @LockName,
@LockMode = 'Exlusive',
@LockTimeout = 0, -- if another process already has the lock, we will skip the update
@lockOwner = 'Session'
IF @rc > 0
BEGIN
-- lock obtained
-- => let's do the cache update
SET @TotalCount = 0
-- fundraising pages
SELECT
egg.EventGivingGroupName as AppealName,
awd.WebDirectoryName as AppealWebDirectory,
c.FirstName,
egg.ImageChoice,
c.LastName,
egg.PhotoUrl,
cwd.WebDirectoryName as ProfileWebDirectory,
eggt.TotalRaisedOffline,
eggt.TotalRaisedOnline,
eggt.TotalContributions,
CAST(egg.DisplayPhoto AS bit) AS DisplayPhoto,
CAST(CASE WHEN ISNULL(dei.DesignEventId, 0) != 0 then 1 else 0 end as bit) as HasStockImages
INTO #staging
FROM
BB02_Event e
INNER JOIN
BB02_EventFundraiserRevenueStream efrs on e.EventId = efrs.EventId
INNER JOIN
BB02_EventGivingGroup egg on efrs.EventFundraiserRevenueStreamId = egg.EventFundraiserRevenueStreamId
INNER JOIN
BB02_EventGivingGroupTotal eggt on egg.EventGivingGroupId = eggt.EventGivingGroupId
INNER JOIN
BB02_Consumer c on c.ConsumerId = egg.ConsumerId
INNER JOIN
BB02_WebDirectory cwd on cwd.WebDirectoryId = c.DefaultWebDirectoryId and cwd.WebDirectoryFamilyId = @PROFILE_LEVEL_WEB_DIR_FAMILY
INNER JOIN
BB02_WebDirectory awd on awd.EventGivingGroupId = egg.EventGivingGroupId and awd.WebDirectoryFamilyId = @PROFILE_APPEAL_WEB_DIR_FAMILY
inner join BB02_DesignEvent de on e.EventId = de.EventId and egg.DesignId = de.DesignId
left join (select distinct DesignEventId from BB02_DesignEventImage) dei on de.DesignEventId = dei.DesignEventId
where eggt.EventGivingGroupTotalTypeId =
case when de.AddFeesToTotal = 1 then @TOTAL_TYPE_REGISTRATION -- 3 includes registration fees
else @TOTAL_TYPE_NON_REJECTED /* 1 = Confirmed, 2 = Not Rejected */
end
and egg.Status <> @PAGE_STATUS_CANCELED
and de.DesignEventId = @DesignEventId
and egg.IsDeleted = 0
SET @TotalCount = @TotalCount + @@ROWCOUNT
-- registrants without pages
INSERT #staging ( AppealName,
AppealWebDirectory,
FirstName,
ImageChoice,
LastName,
PhotoURL,
ProfileWebDirectory,
TotalRaisedOffline,
TotalRaisedOnline,
TotalContributions,
DisplayPhoto,
HasStockImages,
LastUpdated)
select
'' as AppealName,
'' as AppealWebDirectory,
FirstName,
'' as ImageChoice,
LastName,
'' as PhotoURL,
'' as ProfileWebDirectory,
0 as TotalRaisedOffline,
0 as TotalRaisedOnline,
0 as TotalContributions,
'' as DisplayPhoto,
cast(case when isnull(dei.DesignEventId, 0) != 0 then 1 else 0 end as bit) as HasStockImages
from BB02_ConsumerEventRegistration cer
left join (select distinct DesignEventId from BB02_DesignEventImage) dei on cer.DesignEventId = dei.DesignEventId
where cer.DesignEventId = @DesignEventId
and cer.ConsumerId not in (
select egg.ConsumerId
from BB02_EventGivingGroup egg
inner join BB02_EventFundraiserRevenueStream efrs on efrs.EventFundraiserRevenueStreamId = egg.EventFundraiserRevenueStreamId
inner join BB02_DesignEvent de on efrs.EventId = de.EventId and egg.DesignId = de.DesignId
where de.DesignEventId = @DesignEventId
)
SET @TotalCount = @TotalCount + @@ROWCOUNT
-- out with the old, in with the new
BEGIN TRANSACTION
DELETE FROM BB02_OLR_GetSupportersCache WITH (XLOCK, ROWLOCK, HOLDLOCK)
WHERE designeventid = @DesignEventId
INSERT INTO bb02_olr_getsupporterscache (DesignEventId,
AppealName,
AppealWebDirectory,
FirstName,
ImageChoice,
LastName,
PhotoURL,
ProfileWebDirectory,
TotalRaisedOffline,
TotalRaisedOnline,
TotalContributions,
DisplayPhoto,
HasStockImages,
LastUpdated,
TotalCount)
SELECT DesignEventId = @DesignEventId,
AppealName,
AppealWebDirectory,
FirstName,
ImageChoice,
LastName,
PhotoURL,
ProfileWebDirectory,
TotalRaisedOffline,
TotalRaisedOnline,
TotalContributions,
DisplayPhoto,
HasStockImages,
LastUpdated = CURRENT_TIMESTAMP,
TotalCount = @TotalCount
COMMIT TRANSAcTION
-- don't drop #staging table yet, we'll re-use it for output again right away
SELECT @cache_was_updated = 1
END
ELSE
BEGIN
-- no lock was obtained, simply wait for the lock to be freed as that will
-- be the moment the new data comes available
EXEC @rc = sp_getapplock @Resource = @LockName,
@LockMode = 'Exclusive',
@LockTimeout = 600000, -- 10 minutes should be enough, end-user will be pretty annyoyed anyway =)
@lockOwner = 'Session'
END
-- free the lock agian, we assume reading locks are handled properly
EXEC sp_releaseapplock @Resource = @LockName
END -- cache update required or not?
-- fetch results
SET @sql = Convert(nvarchar(max), N'')
+ N'
SELECT * FROM (
select
TotalCount' + (CASE WHEN @cache_was_updated = 1 THEN ' = @TotalCount' ELSE N'' END) + ',
SupporterId,
AppealName,
AppealWebDirectory,
FirstName,
ImageChoice,
LastName,
PhotoURL,
ProfileWebDirectory,
TotalRaisedOffline,
TotalRaisedOnline,
TotalContributions,
DisplayPhoto,
HasStockImages,
row_number() over (order by ' +
case when @OrderByField IN ('FirstName', 'LastName') then @OrderByField
when @OrderByField = 'TotalRaised' then '(TotalRaisedOnline + TotalRaisedOffline)'
else 'AppealName' end
+ ' ' + @OrderByDirection + ') as rownumber
from ' + (CASE WHEN @cache_was_updated = 1 THEN '#staging' ELSE 'bb02_olr_getsupporterscache where designeventid = @DesignEventId' END) + '
) q
where q.rownumber > @Offset
and q.rownumber <= @Offset + @PageSize
order by rownumber;'
exec sp_executesql @stmt = @sql,
@params = N'@TotalCount int, @DesignEventId int, @Offset int, @PageSize int',
@TotalCount = @TotalCount,
@DesignEventId = @DesignEventId,
@Offset = @Offset,
@PageSize = @PageSize
DROP TABLE #staging
END
-- other part not looked at (yet) as I guess the trouble comes from the refresh, and that's only in the first part as far as I can tell ...
END