SQL Server 2012, VS2015, SSMS 2017

У меня есть запрос, который в настоящее время использует OUTER APPLY, замедляющий запрос. Я знаю, что могу ускорить это, заменив OUTER APPLY предложением LEFT JOIN ON, но OUTER APPLY использует ORDER BY для сортировки таблицы. JOIN не позволит мне использовать ORDER BY. Есть ли обходной путь для этого?

Текущий запрос:

SELECT 
    t1.ItemID,
    ISNULL(DATEDIFF(s, t1.localTimeStamp, t3.localTimeStamp),
    DATEDIFF(s, t1.localTimeStamp, @End)) AS Duration, 
    t1.localTimeStamp AS TimeStamp
FROM 
    CTE1 AS t1
OUTER APPLY 
    (SELECT TOP 1 localTimeStamp
     FROM CTE1 AS t2
     WHERE t2.localTimeStamp > t1.localTimeStamp AND t2.ItemID = t1.ItemID
     ORDER BY t2.localTimeStamp ASC) AS t3

Этот запрос по существу берет элемент и вычисляет продолжительность между записями таблицы для отдельных элементов. Исходной таблицей является CTE1, которая содержит строки с несколькими идентификаторами ItemID, Values и localTimeStamp, которые не расположены в определенном порядке. Я также не мог использовать ORDER BY в предложении WITH CTE.

Новый запрос:

SELECT 
    t1.Value, t1.tName, t1.ItemID, 
    ISNULL(DATEDIFF(s, t1.localTimeStamp, t2.localTimeStamp),
    DATEDIFF(s, t1.localTimeStamp, @End)) AS Duration, 
    t1.localTimeStamp AS TimeStamp
FROM 
    CTE1 t1
LEFT JOIN 
    CTE1 t2 ON t2.localTimeStamp > t1.localTimeStamp AND t2.ItemID = t1.ItemID

Проблема в том, что он займет ВСЕ строки с большими отметками времени, а не только следующую (по порядку localTimeStamp, а не по фактическому номеру строки).

Могу ли я заставить работать Join или есть другой способ сделать это, не замедляя запрос?

(Я знаю, что соединение выполняется быстрее, потому что, хотя я присоединяю значительно больше строк, этот второй запрос все равно превосходит первый.)

Поскольку я уверен, что это будет помечено как повторяющийся вопрос, я хочу указать, что я прочитал много других подобных вопросов на этом сайте об этом, и каждый, кто просит заказать предложение соединения, присоединяется к столбцу1 = столбец2, где порядок неважно, они просто ошибались. поскольку я присоединяюсь к столбцу column1> column2, порядок действительно имеет значение. возможно, решение в том, что я должен использовать внешнее применение, но этот вопрос здесь НЕ задавался.

0
z_temp_string 23 Окт 2018 в 00:27

2 ответа

Лучший ответ

Почему бы просто не использовать lead()?

SELECT tt.ItemID,
       COALESCE(DATEDIFF(second, t.localTimeStamp, LEAD(t.localTimeStamp) OVER (PARTITION BY t.ItemId ORDER BY t.localTimeStamp)),
                DATEDIFF(second, t.localTimeStamp, @End)
               ) as Duration, 
       t.localTimeStamp as TimeStamp
FROM CTE1 t;

Microsoft проделала хорошую работу по оптимизации APPLY. Я предполагаю, что проблема производительности заключается в том, что CTE запускается дважды, и lead() должен исправить это.

3
Gordon Linoff 23 Окт 2018 в 16:20

Измените второй запрос, чтобы использовать

Мин (t2.localtimestamp) и сгруппируйте по остальным столбцам

0
LoztInSpace 22 Окт 2018 в 21:35
52937993