Как отфильтровать условие TOP 1 в предложении WHERE - PullRequest
0 голосов
/ 05 октября 2018

Какой самый эффективный способ устранения записей в предложении WHERE с использованием логики TOP 1?

Таблица tblQuoteStatusChangeLog не входит в JOIN.Но на основании значения в этой таблице мне нужно исключить записи, которые имеют NewQuoteStatusID = 12

. Это работает так, как есть, но я ищу более эффективный способ, так как у меня есть сортировка (Top N Sort)оператор, который слишком широк.

SELECT    
    Q.ControlNo   
    ,sum(fid.amtbilled) as Premium


FROM           
    [dbo].tblQuotes Q 
        inner join [dbo].[tblFin_Invoices] FI  on Q.QuoteID = FI.QuoteID and FI.failed = 0  
        inner join [dbo].[tblFin_InvoiceDetails] FID  on FI.[InvoiceNum] = FID.InvoiceNum  
WHERE       (
            SELECT  TOP 1 NewQuoteStatusID
             FROM    tblQuoteStatusChangeLog
             WHERE   (ControlNo = Q.ControlNo)
             ORDER BY Timestamp DESC
             ) <> 12

Group by
Q.ControlNo

enter image description here

1 Ответ

0 голосов
/ 06 октября 2018

Ваш код RBAR ;выполняя один и тот же подзапрос 1, что очень неэффективно.

Вы беспокоитесь о «сортировке», но это само по себе не будет проблемой.Посмотрите дальше вверх и налево от плана;к вложенному циклу.Посмотрите жирную строку ввода сверху и тонкую чуть ниже.По сути, вы очень часто обращаетесь к своему сорту.

Предложение: попробуйте использовать решение на основе множеств.«Подготовьте» данные, которые требуются для предложения WHERE, «заранее», чтобы вы могли исключить RBAR.Представьте, что у вас есть LatestStatus в виде таблицы со столбцами ControlNo и StatusID.Было бы намного проще применить ваш фильтр;и Оптимизатор запросов должен быть в состоянии найти более эффективный общий план.

Вы можете настроить это с помощью CTE.

;with StatusByControlNo as (
  SELECT  ROW_NUMBER() OVER(PARTITION BY ControlNo ORDER BY Timestamp DESC) AS RowNo,
          ControlNo, Timestamp, NewQuoteStatusID
  FROM    tblQuoteStatusChangeLog
) ...
/*Easy to get Latest status per ControlNo from here*/
SELECT  ControlNo, NewQuoteStatusID
FROM    StatusByControlNo
WHERE   RowNo = 1

Теперь с несколькими настройками ваш запрос становится:

;with StatusByControlNo as (
  SELECT  ROW_NUMBER() OVER(PARTITION BY ControlNo ORDER BY Timestamp DESC) AS RowNo,
          ControlNo, Timestamp, NewQuoteStatusID
  FROM    tblQuoteStatusChangeLog
)
SELECT    
    Q.ControlNo,
    sum(fid.amtbilled) as Premium
FROM           
    tblQuotes Q 
    inner join tblFin_Invoices FI
        on Q.QuoteID = FI.QuoteID and FI.failed = 0
    inner join tblFin_InvoiceDetails FID
        on FI.InvoiceNum = FID.InvoiceNum
    inner join StatusByControlNo S
        on S.ControlNo = Q.ControlNo and S.RowNo = 1
WHERE
    S.ControlNo <> 12
Group by Q.ControlNo

Само собой разумеется, вы можете попробовать несколько вариантов этого.Но основной принцип заключается в сокращении RBAR и поиске решений, которые более «основаны на множествах».

...