#sql #sql-server #query-optimization
#sql #sql-сервер #запрос-оптимизация
Вопрос:
Необходимо обновить таблицу со 100 миллионами записей. Есть ли способ оптимизировать этот запрос?
DECLARE @rows INT = 1;
WHILE @rows > 0
BEGIN
UPDATE TOP(2000) T1
SET T1.SomeUuid = T2.SomeUuid
FROM dbo.Table1 T1
INNER JOIN Table2 T2 ON T1.SomeId = T2.SomeId
AND T1.AnotherId = T2.AnotherId
AND T1.SomeField = T2.SomeField
WHERE T1.SomeUuid IS NULL
SET @rows = @@ROWCOUNT
END
Для объединения таблиц должен использоваться тройной ключ.
Комментарии:
1. Вы могли бы попробовать большие пакеты, например 10000 или 50000.
2. Зачем вам для этого нужен цикл?
3. Часто быстрее восстановить таблицу, создав новую таблицу с измененными значениями, а затем выполнить массовую вставку всех строк.
4. Вы могли бы добавить отфильтрованный индекс с условием where — Index Table1 ДЛЯ SomeId, ГДЕ SomeUuid = null и т.д. Убедитесь, что в Table2 есть индекс для SomeId, AnotherID и someField
Ответ №1:
Вы можете попробовать этот подход и посмотреть, работает ли он для вас. Идея в том, что мы готовим идентификаторы заранее и избегаем этого соединения и других предикатов при простом чтении данных. Поступая таким образом, мы сужаем команду обновления до максимально простой и улучшаем параллелизм. Любой выбранный вами подход, просто помните, что не следует обновлять более нескольких тысяч строк одновременно, чтобы предотвратить эскалацию блокировки.
CREATE TABLE dbo.#data (SomeUuid bigint, AnotherId bigint);
CREATE TABLE dbo.#data_for_iteration (SomeUuid bigint, AnotherId bigint);
-- Get the Ids (Pk or Unique )
INSERT dbo.#data(SomeUuid, AnotherId)
SELECT SomeUuid, AnotherId
FROM dbo.Table1 T1
INNER JOIN Table2 T2 ON T1.SomeId = T2.SomeId
AND T1.AnotherId = T2.AnotherId
AND T1.SomeField = T2.SomeField
WHERE T1.SomeUuid IS NULL;
WHILE 1=1
BEGIN;
DELETE TOP (2000) #data OUTPUT Deleted .SomeUuid INTO #data_for_iteration ( SomeUuid );
-- Exite here when done
IF @@ROWCOUNT = 0 BEGIN; PRINT 'No more data to process. Terminating'; BREAK; END;
UPDATE T1
SET T1.SomeUuid = T2.SomeUuid
FROM dbo.Table1 T1
INNER JOIN #data_for_iteration T2 ON T1.SomeId = T2.SomeId
TRUNCATE TABLE #data_for_iteration;
END;