我不是DBA,而且我没有优化此查询的想法。运行大约需要40多秒。我可以优化哪些明显的新手错误?
USE [deskcal2014]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[proc_AdminRegisteredCards]
(
@Take AS INT,
@Skip AS INT,
@FilterColumn AS NVARCHAR(max),
@FilterOrder AS NVARCHAR(max))
AS
BEGIN
SELECT TOP(@Take)
ISNULL( ROW_NUMBER() OVER(ORDER BY ta.CreatedOn, ta.ItemId), -1000) AS AdminRegisteredCardsId,
ta.ItemId,
ta.CardNumber,
ta.FirstName,
ta.LastName,
ta.Birthday,
ta.PostalCode,
ta.[Description],
ta.CardActivated,
ta.ContactInfo,
ta.PhoneNumber,
ta.ReceiveCalendarReminders,
ta.ReceiveGeneralMails,
ta.ReceivePrefStoreMails,
ta.CardStatus,
ta.SamoaCardId,
ta.CalendarUserId,
ta.LiveOpsRegistrantId,
ta.UseType,
ta.CreatedOn,
ta.ModifiedBy,
ta.ModifiedOn from (
SELECT CalendarUser.CalendarUserId as ItemId,
SamoaCard.CardNumber,
SamoaCard.FirstName,
SamoaCard.LastName,
CalendarUser.Birthday,
CalendarUser.PostalCode,
RegisterSourceType.[Description],
CalendarUserCard.CardActivated,
CalendarUser.EmailAddress as ContactInfo,
CalendarUser.PhoneNumber,
CalendarUser.ReceiveCalendarReminders,
CalendarUser.ReceiveGeneralMails,
CalendarUser.ReceivePrefStoreMails,
CASE WHEN CalendarUserCard.CardDeactivated IS NOT NULL THEN 'Deactivated' ELSE 'Activated' END AS CardStatus,
SamoaCard.SamoaCardId,
CalendarUser.CalendarUserId,
null as LiveOpsRegistrantId,
SamoaCard.CreatedOn,
'C' as UseType,
CalendarUser.ModifiedBy,
CalendarUser.ModifiedOn
FROM (
(dbo.CalendarUser CalendarUser
INNER JOIN dbo.RegisterSourceType RegisterSourceType ON (CalendarUser.RegisterType = RegisterSourceType.RegisterType))
INNER JOIN dbo.CalendarUserCard CalendarUserCard ON (CalendarUserCard.CalendarUserId = CalendarUser.CalendarUserId)
)
INNER JOIN dbo.SamoaCard SamoaCard ON (CalendarUserCard.SamoaCardId = SamoaCard.SamoaCardId)
ORDER BY
case when @FilterColumn = 'FirstName' and @FilterOrder = 'ASC'
then CalendarUser.Firstname end asc,
case when @FilterColumn = 'FirstName' and @FilterOrder = 'DESC'
then CalendarUser.Firstname end desc,
case when @FilterColumn = 'LastName' and @FilterOrder = 'ASC'
then CalendarUser.Lastname end asc,
case when @FilterColumn = 'LastName' and @FilterOrder = 'DESC'
then CalendarUser.Lastname end desc,
case when @FilterColumn = 'CardNumber' and @FilterOrder = 'ASC'
then CalendarUser.CardNumber end asc,
case when @FilterColumn = 'CardNumber' and @FilterOrder = 'DESC'
then CalendarUser.CardNumber end desc,
case when @FilterColumn = 'Birthday' and @FilterOrder = 'ASC'
then CalendarUser.Birthday end asc,
case when @FilterColumn = 'Birthday' and @FilterOrder = 'DESC'
then CalendarUser.Birthday end desc,
case when @FilterColumn = 'Description' and @FilterOrder = 'ASC'
then RegisterSourceType.[Description] end asc,
case when @FilterColumn = 'Description' and @FilterOrder = 'DESC'
then RegisterSourceType.[Description] end desc,
case when @FilterColumn = 'ContactInfo' and @FilterOrder = 'ASC'
then CalendarUser.EmailAddress end asc,
case when @FilterColumn = 'ContactInfo' and @FilterOrder = 'DESC'
then CalendarUser.EmailAddress end desc,
case when @FilterColumn = 'CardActivated' and @FilterOrder = 'ASC'
then CalendarUserCard.CardActivated end asc,
case when @FilterColumn = 'CardActivated' and @FilterOrder = 'DESC'
then CalendarUserCard.CardActivated end desc,
case when @FilterColumn = 'PostalCode' and @FilterOrder = 'ASC'
then CalendarUser.PostalCode end asc,
case when @FilterColumn = 'PostalCode' and @FilterOrder = 'DESC'
then CalendarUser.PostalCode end desc
OFFSET @Skip ROWS -- skip N rows
FETCH NEXT @Take ROWS ONLY
union all
SELECT TOP(10)
LiveOpsRegistrant.LiveOpsRegistrantId as ItemId,
LiveOpsRegistrant.CardNumber,
'Registered' as FirstName,
'Card' as LastName,
LiveOpsRegistrant.Birthday,
null as PostalCode,
'LiveOps' as Description,
LiveOpsRegistrant.CreatedOn as CardActivated,
LiveOpsRegistrant.PhoneNumber as ContactInfo,
LiveOpsRegistrant.PhoneNumber,
CONVERT(bit,0) as ReceiveCalendarReminders,
CONVERT(bit,0) as ReceiveGeneralMails,
CONVERT(bit,0) as ReceivePrefStoreMails,
'Activated' AS CardStatus,
SamoaCard.SamoaCardId,
null as CalendarUserId,
LiveOpsRegistrant.LiveOpsRegistrantId,
SamoaCard.CreatedOn,
'L' as UseType,
SamoaCard.ModifiedBy,
SamoaCard.ModifiedOn
FROM dbo.LiveOpsRegistrant LiveOpsRegistrant
INNER JOIN dbo.SamoaCard SamoaCard ON (LiveOpsRegistrant.CardNumber = SamoaCard.CardNumber)) ta
END
GO
答案 0 :(得分:0)
回应已经给出的一些评论:在ORDER BY
子句中包含一堆逻辑通常不能很好地工作。 ROW_NUMBER()
在具有许多联接和其他复杂性的查询中使用时可能会很糟糕。
临时表可能是你的第一个最佳选择。阅读你的代码,我认为第一个代码是CalendarUser.CalendarUserId,你需要用一堆嵌套的if ... else if语句填充它:
if @FilterColumn = 'FirstName' and @FilterOrder = 'ASC'
begin
insert into #CalendarUser
select top(@Take) CalendarUserId
order by Firstname asc
offset @Skip rows
fetch next @Take rows only
end
else
begin
if .....
使用#CalendarUser上的内部联接来填充第二个临时表#DataOut
,其中包含您要输出的所有字段,以过滤结果集。使用ROW_NUMBER()
排除您正在计算的字段。将UNION ALL
保留在此查询之外,将其中的数据作为单独步骤附加到#DataOut
表中。
最终输出查询将是
select
ISNULL( ROW_NUMBER() OVER(ORDER BY CreatedOn, ItemId), -1000)
AS AdminRegisteredCardsId,
#DataOut.*
from #DataOut
写作不愉快,感觉蛮力,但我相信你会看到戏剧性的表现改善。
答案 1 :(得分:0)
我一直在尝试优化类似的查询,并得出结论,跨连接的排序和过滤对性能有很大的影响 - 我的建议是对使用索引视图进行排序或过滤的所有内容进行非规范化处理看看这会对表现产生什么影响。