2015-04-07 2 views
0

У меня есть фрагмент кода SQL, который сравнивает последние две записи и дает datediff в считанные секунды, однако способ, которым я занимаюсь, довольно медленный, занимая до 20 секунд, чтобы выполнить в зависимости от того, сколько мне требуется идентификаторов контроллера проверить.Плохая производительность с sql-запросом

Что было бы более эффективным способом сделать это?

select 
    T.controllerID, 
    datediff(ss, T.Max_dtReading, T1.Max_dtReading) As ElaspedTime 
from 
    (select 
     controllerID, 
     max(dtReading) as Max_dtReading 
    from 
     ReaderData 
    where 
     CardID = 'FFFFFFF0' AND (controllerID in(2,13,28,30,37,40)) 
    group by 
     controllerID) as T 
outer apply 
    (select 
     max(T1.dtReading) as Max_dtReading 
    from 
     ReaderData as T1 
    where 
     T1.CardID = 'FFFFFFF0' AND (controllerID in(2,13,28,30,37,40)) 
     and T1.controllerID = T.controllerID 
     and T1.dtReading < T.Max_dtReading) as T1 
+0

Какую версию SQL Server вы используете? –

+0

Sql server 2008 –

ответ

3

Я мог бы предложить условную агрегации для этого:

select controllerID, 
     datediff(second, max(dtReading), min(dtReading) 
       ) As ElaspedTime 
from (select controllerID, dtReading, 
      row_number() over (partition by controllerID order by dtReading desc) as seqnum 
     from ReaderData 
     where CardID = 'FFFFFFF0' AND 
      controllerID in (2, 13, 28, 30, 37, 40) 
    ) r 
where seqnum <= 2 
group by controllerID 
+0

Спасибо, что это заняло это от 20 + секунд до 2 секунд! благодаря –

1
;WITH CTE AS 
(select controllerID 
     ,dtReading 
     ,ROW_NUMBER() OVER (PARTITION BY controllerID ORDER BY dtReading DESC) rn 
    from ReaderData 
    where CardID = 'FFFFFFF0' 
    AND controllerID IN (2,13,28,30,37,40) 
) 
select C1.controllerID 
     ,datediff(ss, C1.dtReading, C2.dtReading) As ElaspedTime 
from CTE C1 
LEFT JOIN CTE C2 ON C1.controllerID = C2.controllerID 
       AND C1.rn = 1 
       AND C1.rn < C2.rn 
1

Вы можете использовать ROW_NUMBER() для того, чтобы найти записи с 2-х самых высоких dtReading значений, а затем присоединиться к этим вместе, чтобы вычислить разницу :

;WITH CTE AS (
    SLEECT controllerID, dtReading, 
      ROW_NUMBER() OVER (PARTITION BY controllerID 
           ORDER BY dtReading DESC) AS rn   
    FROM ReaderData 
    WHERE CardID = 'FFFFFFF0' AND (controllerID IN (2,13,28,30,37,40)) 
)  
SELECT c1.controllerID, 
     DATEDIFF(ss, c1.dtReading, c2.dtReading) AS ElaspedTime 
FROM CTE c1 
INNER JOIN CTE c2 ON (c1.controllerID = c2.controllerID) 
        AND c1.rn = 1 AND c2.rn = 2