2

我有一個表我想做分頁和排序,並且能夠得到類似於下面的查詢來完成這項工作(真正的查詢涉及更多與連接等)。Row_Number()CTE使用ORDER BY CASE時的性能

WITH NumberedPosts (PostID, RowNum) AS 
(
    SELECT PostID, ROW_NUMBER() OVER (ORDER BY 
     CASE WHEN @sortCol = 'User' THEN User END DESC, 
     CASE WHEN @sortCol = 'Date' THEN Date END DESC, 
     CASE WHEN @sortCol = 'Email' THEN Email END DESC) as RowNum 
    FROM Post 
) 
INSERT INTO #temp(PostID, User, Date, Email) 
SELECT PostID, User, Date, Email 
FROM Post 
WHERE NumberedPosts.RowNum BETWEEN @start and (@start + @pageSize) 
     AND NumberedPosts.PostID = Post.PostID 

麻煩的是使用CASE語句(至少10倍的減速)時,與正常ORDER BY Date desc子句時性能大大降低。查看查詢計劃,即使它們不匹配@sortCol限定符,也會顯示所有列仍在排序。

有沒有辦法讓它以接近'原生'的速度執行?動態SQL是這個問題的最佳人選嗎?謝謝!

+0

你有一個三級排序(3 DESC和2個逗號)。爲什麼不僅僅使用單個案例來處理多個案件? – 2010-07-13 02:52:58

回答

2

我肯定會下去動態SQL路由(使用帶參數的sp_executesql來避免任何注入攻擊)。使用CASE方法,您立即阻止SQL Server使用任何有助於排序過程的相關索引。

3

更好的做法是使用三種硬編碼查詢(在基於@sortCol的適當IF語句中)或動態SQL。

你可以用三個不同的查詢(基於一個基本的CTE來完成你所有的JOIN)來做一個詭計,其中只有一個返回@sortCol的行,但是我必須在它之前進行配置推薦它:

WITH BasePosts(PostID, User, Date, Email) AS (
    SELECT PostID, User, Date, Email 
    FROM Posts -- This is your complicated query 
) 
,NumberedPosts (PostID, User, Date, Email, RowNum) AS 
(
    SELECT PostID, User, Date, Email, ROW_NUMBER() OVER (ORDER BY User DESC) 
    FROM BasePosts 
    WHERE @sortCol = 'User' 

    UNION ALL 

    SELECT PostID, User, Date, Email, ROW_NUMBER() OVER (ORDER BY Date DESC) 
    FROM BasePosts 
    WHERE @sortCol = 'Date' 

    UNION ALL 

    SELECT PostID, User, Date, Email, ROW_NUMBER() OVER (ORDER BY Email DESC) 
    FROM BasePosts 
    WHERE @sortCol = 'Email' 
) 
INSERT INTO #temp(PostID, User, Date, Email) 
SELECT PostID, User, Date, Email 
FROM NumberedPosts 
WHERE NumberedPosts.RowNum BETWEEN @start and (@start + @pageSize) 
+0

我在查看原始查詢之後更新了我的答案 - 一個沒有其他結果的情況下會產生一個NULL,這些都會排在一起,但這就是爲什麼它仍然會對所有內容進行排序。 – 2010-07-13 03:24:19

2

應該沒有任何理由來查詢發佈表兩次。您可以轉到動態路由並解決性能問題或創建由@sortCol參數確定的3個查詢。冗餘代碼除了row_num和按部件排序外,但有時如果速度很關鍵,則會放棄可維護性。

If @sortCol = 'User' 
Begin 
    Select... Order by User 
End 

If @sortCol = 'Date' 
Begin 
    Select .... Order by Date 
end 

If @sortCol = 'Email' 
Begin 
    Select... Order by Email 
End 
+0

我甚至沒有看他的代碼的底部,看他是否會回到帖子,你是絕對正確的,這是不必要的,我已經清理了我的答案。 – 2010-07-13 01:08:20

0

這應該工作,但不知道這是否可以提高性能:

WITH NumberedPosts (PostID, RowNum) AS 
(
    SELECT PostID, ROW_NUMBER() OVER (ORDER BY 
     CASE WHEN @sortCol = 'User' THEN User 
      WHEN @sortCol = 'Date' THEN Date 
      WHEN @sortCol = 'Email' THEN Email 
     END DESC) as RowNum 
    FROM Post 
) 
INSERT INTO #temp(PostID, User, Date, Email) 
SELECT PostID, User, Date, Email 
FROM Post 
WHERE NumberedPosts.RowNum BETWEEN @start and (@start + @pageSize) 
     AND NumberedPosts.PostID = Post.PostID 
+1

這個例子實際上有問題,我以爲原來的查詢有:不同的列(可能)是不同的數據類型,用戶和日期和電子郵件都將被轉換爲相同的類型。 瞭解了這一點,根據轉換爲varchar,您的ORDER BY CONVERT(varchar(?),Date)可能甚至無法正常工作(除非它已經是YYYY-MM-DD形式的varchar,在這種情況下,很可能排序好的)。 – 2010-07-13 03:22:57