2016-06-24 2 views
0

У меня есть таблица, которая охватывает 200 миллионов записей, и я пытаюсь запустить следующий запрос. Запрос пытается обновить таблицу на основе метки времени из предыдущей записи. Есть ли способ сделать этот запрос быстрее?Настройка кросс-записи UPDATE-запрос

UPDATE [dbo].[Location Data] 
    SET [timestamp_prev] = 
    (
      SELECT [timestamp] FROM [dbo].[Location Data] newTable 
       WHERE [dbo].[Location Data].[RowNumber] = (newTable.[RowNumber] + 1) 
       AND [dbo].[Location Data].[mmsi] = newTable.[mmsi] 
    ); 
+0

Проверьте план запроса: действительно ли он выполняет коррелированный подзапрос, или он перевел его в самостоятельное объединение? Если нет, вы должны это сделать. – Blorgbeard

+0

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

ответ

2

Вы можете попробовать использовать автообъединение:

UPDATE 
    t1 
SET 
    t1.[timestamp_prev] = t2.[timestamp] 
FROM 
    [dbo].[Location Data] t1 
INNER JOIN 
    [dbo].[Location Data] t2 
    ON t1.[RowNumber] = t2.[RowNumber] + 1 AND 
     t1.[mmsi] = t2.[mmsi] 

Если у вас есть индексы на объединяемых столбцов этот запрос может завершиться до вы уходите на пенсию.

0

Внутреннего соединение, как показано ниже может помочь, а не перебор всех строк таблицы в каждую строку таблицы, как это было бы в вашем вложенном запросе.

UPDATE oldTable 
SET oldTable.[timestamp_prev] = newTable.[timestamp] 
FROM [dbo].[Location Data] oldTable 
INNER JOIN [dbo].[Location Data] newTable 
    ON oldTable.[RowNumber] = newTable.[RowNumber] + 1 
       AND oldTable.[mmsi] = newTable.[mmsi] 
0

Я хотел бы попробовать что-то вроде этого:

UPDATE T1 SET 
    [timestamp_prev] = T2.[timestamp] 
FROM [dbo].[Location Data] T1 
    INNER JOIN [dbo].[Location Data] T2 
     ON T1.RowNumber = T2.RowNumber + 1 
      AND T1.mmsi = T2.mmsi 
WHERE T1.[timestamp_prev] IS NULL; 

Объединение должно быть более эффективным и только пытаться обновить записи, которые не имеют предыдущую метку. Затем вы можете сделать еще один шаг, чтобы добавить индекс в RowNumber, MMSI и Timestamp_Prev в таблицу, которая затем обеспечила бы, чтобы чистый индекс стремился максимизировать эффективность.

Простой индекс, как это должно быть хорошее начало:

CREATE NONCLUSTERED INDEX ix_Location_Data_MMSI_RowNumber_Timestamp_Prev 
    ON dbo.[Location Data] (mmsi, RowNumber, Timestamp_Prev) INCLUDE (Timestamp); 
2

Во-первых, я хотел бы сделать это с помощью lag():

with toupdate as (
     select ld.*, 
      lag(timestamp) over (partition by mmsi order by RowNumber) as prev_timestamp 
     from dbo.[Location Data] ld 
    ) 
update toupdate 
    set timestamp_prev = prev_timetamp; 

Тогда я хотел бы отметить, что обновление 200 миллионов записей собирается занять долгое, долгое, долгое время. Я бы предположил, что вы создаете новую таблицу с нужными столбцами, затем обрезаете исходную таблицу и повторно заполняете ее.

+1

Nice one ** lag **. Не знал, что это даже существовало! – Sam

+1

@Sam [LAG] (https://msdn.microsoft.com/en-IN/library/hh231256.aspx) был введен в 'SQL SERVER 2012' –

+2

@Prdp Я думаю, что Сэм был« LAG »за :-) –

Смежные вопросы