我有一个表,我想做分页和排序,并且能够得到类似于以下的查询来完成工作(真正的查询更多地涉及连接等)。
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
问题在于,与普通ORDER BY Date desc
子句相比,使用CASE语句(至少10倍减速)时性能会严重下降。查看查询计划,看起来所有列仍在排序,即使它们与@sortCol限定符不匹配。
有没有办法让它以接近'原生'的速度执行?动态SQL是这个问题的最佳候选者吗?谢谢!
答案 0 :(得分:3)
最好使用三个硬编码查询(在基于@sortCol的适当IF语句中)或动态SQL执行此操作。
你可能可以使用UNION ALL三个不同的查询(基于执行所有JOIN的基础CTE),其中只有一个返回@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)
答案 1 :(得分:2)
我肯定会继续使用动态SQL路由(使用带参数的sp_executesql来避免任何注入攻击)。使用CASE方法,您可以立即阻止SQL Server使用任何有助于排序过程的相关索引。
答案 2 :(得分: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
答案 3 :(得分: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