我构建了一个非常简单的查询,在使用CASE语句时使用时非常长。你能提出任何见解吗?
示例1:没有CASE语句。运行< 1秒
select * from
(
select
(row_number() over (order by b.BookName)) as RowNumber,
b.*
from
Books b (nolock)
inner join BookPublishRegions p (nolock)
on b.BookKey = bp.BookKey
where
contains(p.PublishRegionName, 'France')
) as t1
where t1.RowNumber between 100 and 110
示例2:使用CASE语句需要30秒以上
select * from
(
select
case @SortBy
when 'Price' then
(row_number() over (order by b.Price))
else
(row_number() over (order by b.BookName))
end as RowNumber,
b.*
from
Books b (nolock)
inner join BookPublishRegions p (nolock)
on b.BookKey = bp.BookKey
where
contains(p.PublishRegionName, 'France')
) as t1
where t1.RowNumber between 100 and 110
我实际上使用上述硬编码值按原样运行这些查询。硬编码值的参数替换没有任何好处。
编辑:明确选择列而不是b。*也没有任何好处。
有什么想法吗?
答案 0 :(得分:1)
你能试试这个版本吗?
select * from
(
select row_number() over (order by b.Price) as rn_price,
row_number() over (order by b.BookName) as rn_bookname,
b.*
from
Books b (nolock)
inner join BookPublishRegions p (nolock)
on b.BookKey = bp.BookKey
where
contains(p.PublishRegionName, 'France')
) as t1
where (t1.rn_price between 100 and 110 and @SortBy = 'Price') or
(t1.rn_name between 100 and 110 and @SortBy <> 'Price')
我怀疑这也会很慢。实际上,您可能遇到无法使用排序选项加速此查询的情况。我想你有Books(BookName)
和Books(Price)
的索引。这些索引用于join
,因为SQL Server足够聪明,可以识别索引对row_number()
有用,因此按顺序返回行是一个很好的优化。那么问题是只能使用其中一个索引,因此case
逻辑(或多个行号)会阻止这种优化。
这只是一个猜测,但它可能会使您的查询更加困难。
如果这是问题,那么您可以使用动态SQL解决它。这将为特定选项创建SQL,优化器将做正确的事情。
答案 1 :(得分:0)
如果您使用的是Sql Server 2012+
,请使用OFFSET-FETCH
方法代替Row_number
。试试这个。
SELECT b.*
FROM Books b (nolock)
INNER JOIN BookPublishRegions p (nolock)
ON b.BookKey = bp.BookKey
WHERE CONTAINS(p.PublishRegionName, 'France')
ORDER BY ( CASE
WHEN @SortBy = 'Price' THEN Price
END ),
( CASE
WHEN @SortBy = 'Price' THEN NULL
ELSE b.BookName
END )
OFFSET 99 ROWSFETCH NEXT 11 ROWS ONLY;
答案 2 :(得分:0)
我无法测试此查询,但我认为将案例INSIDE放在row_number函数中可以解决您的问题。
select * from
(
select
(row_number() over (case @SortBy when 'Price' then b.Price else b.BookName end))
as RowNumber,
b.*
from
Books b (nolock)
inner join BookPublishRegions p (nolock)
on b.BookKey = bp.BookKey
where
contains(p.PublishRegionName, 'France')
) as t1
where t1.RowNumber between 100 and 110