2013-04-02 70 views
0

我有存儲SQL提高case語句爲了條款

ALTER procedure [dbo].[TNNews_User_SearchBasic] 
    @Title nvarchar(400), 
    @CategoryId int, 
    @IsInterested int, 
    @IsHot int, 
    @IsTopCategory int, 
    @IsPublish int, 
    @PageSize int, 
    @PageIndex int, 
    @OrderBy varchar(20), 
    @PortalId int, 
    @LanguageId varchar(6) 
as 

DECLARE @EndTime DATETIME 
DECLARE @StartTime DATETIME 
    SET @StartTime = GETDATE() 

    declare @tbCategory table(Id int) 
    DECLARE @StartRowIndex INT 
    IF @PageSize=0 SELECT @PageSize=count(*) FROM TNNews 
     IF(@PageIndex<0) SET @PageIndex=0 
     SET @StartRowIndex = @PageSize*(@PageIndex-1)+1 

    ;WITH tmpCategory(Id, Name,ParentId,Level) 
    AS (
     SELECT 
      e.Id, 
      e.Name, 
      e.ParentId, 
      1 
     FROM dbo.TNCategory AS e 
     WHERE 
     Id = @CategoryId or (@CategoryId='' and ParentId<=0) 
     UNION ALL 
     SELECT 
      e.Id, 
      e.Name, 
      e.ParentId, 
      Level + 1 
     FROM dbo.TNCategory AS e 
     JOIN tmpCategory AS d ON e.ParentId = d.Id 
     ) 
    insert @tbCategory select Id from tmpCategory 

     ;WITH tmpNews as 
     (
      SELECT 
      a.Id,a.Title,a.Subject 
      ,ROW_NUMBER() OVER (ORDER BY (Publisheddate) desc) as ThuTuBanGhi 
      FROM dbo.TNNews a 
      where 1 = 1 
      --and (Title like '%'[email protected]+'%') 
      and (@CategoryId = -1 or exists (select 0 from @tbCategory b where b.Id = a.CategoryId)) 
      and (@IsInterested = -1 or IsIntrested = @IsInterested) 
      and (@IsHot = -1 or IsHot = @IsHot) 
      and (@IsTopCategory = -1 or IsTopCategory = @IsTopCategory) 
      and (@IsPublish = -1 or IsPublished = @IsPublish) 
      and [email protected] 
      and LanguageId = @LanguageId 
     ) 
     select *, (select COUNT(Id) from tmpNews) as 'TongSoBanGhi' from tmpNews 
     WHERE 
      ThuTuBanGhi BETWEEN (@StartRowIndex) AND (@StartRowIndex + @PageSize-1) 


SET @EndTime = GETDATE() 
PRINT 'StartTime = ' + CONVERT(VARCHAR(30),@StartTime,121) 
PRINT ' EndTime = ' + CONVERT(VARCHAR(30),@EndTime,121) 
PRINT ' Duration = ' + STR(DATEDIFF(MILLISECOND,@StartTime,@EndTime)) + ' millisecond' 

select STR(DATEDIFF(MILLISECOND,@StartTime,@EndTime)) 

這家店後EXCUTE

EXEC [dbo].[TNNews_User_SearchBasic] 
     @Title='', 
     @CategoryId = '', 
     @IsInterested = -1, 
     @IsHot = -1, 
     @IsTopCategory = -1, 
     @IsPublish = -1, 
     @PageSize = 20, 
     @PageIndex = 1, 
     @OrderBy = '', 
     @PortalId = 0, 
     @LanguageId = N'vi-VN' 

go 

的時間EXCUTE關於 「200毫秒」。我創建了一個新店「TNNews_User_SearchBasic1」,並做了一些改變。

..... 
--,ROW_NUMBER() OVER (ORDER BY (Publisheddate) desc) as ThuTuBanGhi 
,ROW_NUMBER() OVER (ORDER BY (case when @OrderBy='VIEW_COUNT' then ViewCount else PublishedDate end) desc) as ThuTuBanGhi 
..... 

現在的時間EXCUTE這家店

EXEC [dbo].[TNNews_User_SearchBasic1] 
     @Title='', 
     @CategoryId = '', 
     @IsInterested = -1, 
     @IsHot = -1, 
     @IsTopCategory = -1, 
     @IsPublish = -1, 
     @PageSize = 20, 
     @PageIndex = 1, 
     @OrderBy = '', 
     @PortalId = 0, 
     @LanguageId = N'vi-VN' 

GO 

約900毫秒。 我不明白爲什麼會有變化。請幫我改進這些商店。

PS:我把實例Db在:http://anhquan22.tk/Portals/0/Videos/web.rar

+0

SQL Server是在優化'ROW_NUMBER OVER(ORDER BY ...)()... BETWEEN @X和非常好的@通過簡化ORDER BY子句中的數據收集直接進行查詢。然而,由於它依賴於'CASE',所生成的計劃變得不理想(因爲計劃被緩存以供重用)。 ***通用***計劃即使與前一個SP的效果相同,也會被創建並執行。 – RichardTheKiwi

回答

0

成品分析你的數據庫結構。問題的一部分隱藏在表結構中。 我已爲您準備好備份。其中,我略微修改了方案以提高性能,並對錶格進行了標準化。您可以從this link下載它。

...你的問題,我會做這樣的 -

DECLARE @SQL NVARCHAR(1000) 
SELECT @SQL = N' 
;WITH tmpCategory (Id, Name, ParentId, [Level]) AS 
(
SELECT 
    e.Id 
, e.Name 
, e.ParentId 
, 1 
FROM dbo.TNCategory e 
WHERE Id = @CategoryId OR (@CategoryId = '''' AND ParentId <= 0) 

UNION ALL 

SELECT 
    e.Id 
, e.Name 
, e.ParentId 
, [Level] + 1 
FROM dbo.TNCategory e 
JOIN tmpCategory d ON e.ParentId = d.Id 
) 
SELECT 
    a.Id 
, ROW_NUMBER() OVER (ORDER BY ' + 
    CASE WHEN @OrderBy = 'VIEW_COUNT' 
    THEN 'ViewCount' 
    ELSE 'PublishedDate' 
    END +' DESC) AS ThuTuBanGhi 
FROM dbo.TNNewsMain a 
where PortalId = @PortalId 
AND LanguageId = @LanguageId' 
+ CASE WHEN @IsInterested != -1 THEN ' AND IsInterested = @IsInterested' ELSE '' END 
+ CASE WHEN @IsHot != -1 THEN ' AND IsHot = @IsHot' ELSE '' END 
+ CASE WHEN @IsTopCategory != -1 THEN ' AND IsTopCategory = @IsTopCategory' ELSE '' END 
+ CASE WHEN @IsPublish != -1 THEN ' AND IsPublish = @IsPublish' ELSE '' END 
+ CASE WHEN @CategoryId != -1 THEN '' ELSE ' AND EXISTS(SELECT 1 FROM tmpCategory b WHERE b.Id = a.CategoryId)' END 

INSERT INTO @temp (Id, ThuTuBanGhi) 
EXECUTE sp_executesql 
@SQL 
, N'@PortalId INT 
, @LanguageId VARCHAR(6) 
, @CategoryId INT 
, @IsInterested INT 
, @IsHot INT 
, @IsTopCategory INT 
, @IsPublish INT' 
, @PortalId = @PortalId 
, @LanguageId = @LanguageId 
, @CategoryId = @CategoryId 
, @IsInterested = @IsInterested 
, @IsHot = @IsHot 
, @IsTopCategory = @IsTopCategory 
, @IsPublish = @IsPublish; 

SELECT 
    d.Id 
, tm.Title 
, tm.[Subject] 
, d.ThuTuBanGhi 
, c.TongSoBanGhi 
FROM (
SELECT t.Id 
, t.ThuTuBanGhi 
FROM @temp t 
WHERE t.ThuTuBanGhi BETWEEN @StartRowIndex AND @StartRowIndex + @PageSize - 1 
) d 
JOIN TNNewsMain tm ON d.Id = tm.Id 
CROSS JOIN (
SELECT TongSoBanGhi = (SELECT COUNT(1) FROM @temp) 
) c