Оптимизация удаления дубликатов SQL с помощью ROW_NUMBER - PullRequest
2 голосов
/ 03 апреля 2012

Я пытаюсь удалить избыточные строки из таблицы SQL, [InfoBucket], со столбцами:

[ID] (varchar(16)), [column1], ... [columnN], [Speed] (bigint)

([column1 ... N] - типы данных, начиная от целых чисел и заканчивая объектами varchar ())различной длины.)

В таблице есть строки с одинаковым значением в столбцах [ID] и некоторых столбцах [column1 ... N].Я беру все эти дубликаты и удаляю все, кроме строки, которая имеет наибольшую [Скорость].

В [InfoBucket] есть приблизительно 400 миллионов строк.

Чтобы разделить работу науправляемые чанки, у меня есть другая таблица, [UniqueIDs], с одним столбцом:

[ID] (varchar (16))

и которая заполняется так:

begin

insert into [UniqueIDs]

select distinct [ID] from [InfoBucket]

end

go

В [UniqueIDs] есть приблизительно 15 миллионов строк.

Я использовал превосходный ответ Мартина Смита на похожий вопрос :

Моя процедура в настоящее время выглядиткак это:

begin

declare @numIDs int

set @numIDs = 10000

;with toRemove as
(

select ROW_NUMBER over (partition by

[ID],
[column1],
...
[columnN]

order by [Speed] desc) as 'RowNum'

from [InfoBucket]

where [ID] in
(

select top (@numIDs) [ID] from [UniqueIDs] order by [ID]

)

)

delete toRemove

where RowNum > 1

option (maxdop 1)

;

;with IDsToRemove as
(

select top (@numIDs) [ID] from [UniqueIDs] order by [ID]

)

delete IDsToRemove

option (maxdop 1)

end

go

Есть некластеризованные индексы на [ID] в [InfoBucket] и [UniqueIDs], а «разбиение по ...» в предложении over включает только столбцы, которые должнысравните.

Теперь моя проблема в том, что для выполнения этой процедуры требуется чуть более шести минут.Регулировка значения @numIDs изменяет время работы линейным образом (т. Е. Когда значение @numIDs равно 1000, процедура выполняется в течение приблизительно 36 секунд (6 минут / 10), а когда значение @numIDs имеет значение1 000 000 Процедура выполняется в течение приблизительно 10 часов (6 минут * 100), это означает, что удаление всех дубликатов в [InfoBucket] занимает дни.

Я попытался добавить столбец uniqueidentifier, [UI_ID] в[InfoBucket] и создание кластеризованного индекса для него (таким образом, [InfoBucket] имел один кластеризованный индекс в [UI_ID] и один некластеризованный в [ID]), но это фактически увеличило время выполнения.

Есть ли способ, которым я могудальше оптимизировать это?

1 Ответ

0 голосов
/ 04 апреля 2012

Ключ в том, чтобы найти подходящее место для удаления строк. Поиграйте с @numIds, чтобы найти самый быстрый шаг, а затем просто дайте ему взбить.

Это 400 миллионов строк, он не завершит весь процесс за считанные минуты, а может и часы, это займет время. Пока таблица не заполняется быстрее, чем вы можете удалить дубликаты, все в порядке.

Найдите сладкое место, затем запланируйте его частое выполнение и выход из пика. Затем время от времени проверяйте процесс, чтобы убедиться, что сладкое пятно остается сладким.

Единственное, о чем я могу подумать, - это вычислить дубликаты, не удаляя их. Это сэкономит время. Особенно, если вы можете вычислить дубликаты в одном выражении SQL, а затем поместить эти данные в еще одну таблицу (например, DupeIdsToDelete, а затем запустить цикл удаления для этих идентификаторов)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...