Низкая производительность в запросе UPDATE на основе SELECT TOP 1

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

Обновляемая таблица table1 содержит менее 1000 записей, но запрашиваемая таблица находится в диапазоне 100 миллионов. Странно то, что я использую почти один и тот же запрос для самых старых и самых последних значений, но запрос для самого последнего значения возвращается через две секунды. Это запрос для самого старого значения; для запуска требуется более двух минут:

UPDATE table1
SET firstVal = (
                    SELECT TOP 1 val 
                    FROM table2 
                    WHERE table1.ID = ID
                    AND valID = 123
                    ORDER BY entryDate
                    )

Запрос для самого последнего, возвращается через две секунды:

UPDATE table1
SET lastVal = (
                    SELECT TOP 1 val 
                    FROM table2  
                    WHERE table1.ID = ID
                    AND valID = 123
                    ORDER BY entryDate DESC
                    )

Индекс:

CREATE NONCLUSTERED INDEX [table2_IX9] ON [dbo].[table2]
(
    [valID] ASC,
    [entryDate] ASC,
    [ID] ASC
)
INCLUDE (   [val]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [AB]
GO

Поиск индекса (не в кластере) Стоимость: 68%
Максимальная стоимость: 29%

Можно ли сформулировать этот запрос для лучшей оптимизации? Есть ли что-то, что мне нужно по-другому на стороне индекса? Заранее спасибо за любое руководство!

2 ответа

Это слишком долго для комментариев, но это может работать быстрее:

UPDATE T1
SET firstVal = T2.val
FROM Table1 T1
     --This might need to be an OUTER APPLY, but impossible to tell from your post
     CROSS APPLY (SELECT TOP 1 ca.val
                  FROM Table2 ca
                  WHERE ca.ID = T1.ID
                    AND ca.valID = 123
                  ORDER BY ca.entryDate) T2;

То, как вы это делаете, может означать, что запрос выполняется отдельно для каждой строки, а не как набор данных. Этот способ заставит запрос работать как набор данных.

Что я в итоге сделал:

SELECT ID, val, entryDate
INTO #tmpT2
FROM table2 
WHERE ID IN (SELECT ID FROM table1)
AND valID = 123

А затем с небольшими изменениями поменяйте местами #tmpT2 для table2 в исходном запросе:

UPDATE table1
SET firstVal = (
                    SELECT TOP 1 val 
                    FROM #tmpT2 
                    WHERE table1.ID = ID
                    ORDER BY entryDate
                    )

Почему: Просто осознал, что с индексированием, которое выглядит точно так, как оно должно было выглядеть, а table1 был очень маленьким, я мог просто попытаться использовать временную таблицу и извлечь все идентификаторы, vals и entryDates для valID = 123 во временную таблицу., Этот шаг занял одну секунду, и использование исходного запроса было мгновенным. Спасибо, что нашли время, чтобы обдумать эту проблему и предложить идеи!

Другие вопросы по тегам