Reputation: 2907
I've constructed a very simple query that's taking extremely long when using a CASE statement versus without. Could you please offer any insight?
Example 1: No CASE statement. Runs < 1s
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
Example 2: Using CASE statement takes over 30 seconds
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
I've actually run those queries as-is with the above hardcoded values. Parameter substitution for hardcoded values offers no benefit.
EDIT: Explicitly selecting the columns instead of b.* also offers no benefit.
Any thoughts?
Upvotes: 1
Views: 1359
Reputation: 2896
I can't test this query but I think putting the case INSIDE the row_number function may solve your problem.
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
Upvotes: 0
Reputation: 1269933
Can you try this version?
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')
I suspect this will also be slow. In fact, you might have a situation where you just cannot speed up this query with options on the sort. I am thinking that you have an index on Books(BookName)
and Books(Price)
. These indexes get used for the join
because SQL Server is smart enough to recognize that the index is useful for the row_number()
, so returning the rows in order by the desired column is a good optimization. The problem would then be that only one of these indexes could be used, so the case
logic (or multiple row numbers) would prevent this optimization.
This is just a guess, but it might make optimizing your query rather difficult.
If this is the issue, then you can solve it by using dynamic SQL. That would create the SQL for the specific option, and the optimizer would do the right thing.
Upvotes: 1
Reputation: 93724
If you are using Sql Server 2012+
the use OFFSET-FETCH
approach instead of Row_number
. Try this.
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;
Upvotes: 0