0

I want to know if the SQL Server query optimizer is ever smart enough to look inside a CASE expression when it figures out execution plans.

For purposes of reporting, I have written a view that encapsulates logic for classifying records. It adds a "status" column based on a number of lookups elsewhere in the database. Here's a simple example:

create view LibraryBook_with_Status
as
select
    LibraryBook.*,
    case
        when (some logic) then 'Deleted'
        when (more logic) then 'Checked Out'
        when (more logic) then 'Out for Repair'
        when (more logic) then 'On Hold'
        else 'On the Shelf'
        end as [Status]
from
    LibraryBook 
    left outer join 
    (bunch of other tables used in Status calculation, preserving cardinality)

I would like to use this view in other queries and have SQL Server create execution plans that takes the CASE logic into account. For example:

select * 
from LibraryBook_with_Status 
where [Status] = 'Deleted'

If this query was written referencing only base tables instead of the view, it would only use LibraryBook and those tables in the first clause of the CASE expression. But, based on my rudimentary tests, SQL Server seems to be calculating the status of all rows and then filtering. This is much more inefficient.

If the CASE expression really is a black box, then I see a trade-off between maintainability and query execution speed.

So, is it not possible to encapsulate logic like this without compromise? Is there some way of formulating a view that enables more efficient query plans to be built?

4

2 回答 2

1

有了这样的东西,QO 应该能够根据实际使用的列(在 SELECT 和 WHERE 中)进行连接修剪:

create view LibraryBook_with_Status
as
select
    LibraryBook.*,
    IIF(DeletedBooks.DeletedDate IS NOT NULL, 1, 0) AS IsDeleted,
    IIF(BookCheckout.CheckoutDate IS NOT NULL AND BookCheckout.CheckinDate IS NULL, 1, 0) AS IsCheckedOut,
    IIF(BookRepair.RepairStartDate IS NOT NULL AND BookRepair.RepairEndDate IS NULL, 1, 0) AS IsOutForRepair
from
    LibraryBook 
    left outer join DeletedBooks ON ...
    left outer join BookCheckout ON ...
    left outer join BookRepair ON ...

接着:

select a, b, c  --  columns from LibraryBook
from LibraryBook_with_Status
where IsDeleted = 1
于 2013-07-01T06:44:15.077 回答
1

为什么不将视图设为“全部联合”,其中每个成员子集由具有指示状态的行组成,性能可能会因状态计算的逻辑以及视图在 where 子句中与状态一起使用的频率而异。

只是一个想法。

select
    LibraryBook.*,
    [Status] = 'Deleted'
from LibraryBook
left outer join (bunch of other tables used in Status calculation, preserving cardinality)
where (some logic indicating status is 'Deleted')

union all

select
    LibraryBook.*,
    [Status] = 'Checked Out'
from LibraryBook
left outer join (bunch of other tables used in Status calculation, preserving cardinality)
where (some logic indicating status is 'Checked Out')

union all
    :
于 2013-10-15T21:45:05.793 回答