Удалить большой объем данных на сервере SQL - PullRequest
8 голосов
/ 26 января 2010

Предположим, у меня есть таблица с записью 10000000. В чем разница между этими двумя решениями?

  1. удалить данные как:

    DELETE FROM MyTable
    
  2. удалить все данные строкой за строкой приложения:

    DELETE FROM MyTable WHERE ID = @SelectedID
    

У первого решения наилучшая производительность? Как это влияет на журнал и производительность?

Ответы [ 7 ]

21 голосов
/ 26 января 2010

Если вам нужно ограничиться тем, какие строки нужно удалить, и не выполнять полное удаление, или вы не можете использовать TRUNCATE TABLE (например, на таблицу ссылается ограничение FK или она включена в индексированное представление), Вы можете сделать удаление кусками:

DECLARE @RowsDeleted INTEGER
SET @RowsDeleted = 1

WHILE (@RowsDeleted > 0)
    BEGIN
        -- delete 10,000 rows a time
        DELETE TOP (10000) FROM MyTable [WHERE .....] -- WHERE is optional
        SET @RowsDeleted = @@ROWCOUNT
    END

Как правило, TRUNCATE - лучший способ, и я бы использовал его, если это возможно. Но это не может быть использовано во всех сценариях. Также обратите внимание, что TRUNCATE будет сбрасывать значение IDENTITY для таблицы, если она есть.

Если вы используете SQL 2000 или более раннюю версию, условие TOP недоступно, поэтому вы можете использовать вместо него SET ROWCOUNT.

DECLARE @RowsDeleted INTEGER
SET @RowsDeleted = 1
SET ROWCOUNT 10000 -- delete 10,000 rows a time

WHILE (@RowsDeleted > 0)
    BEGIN
        DELETE FROM MyTable [WHERE .....] -- WHERE is optional
        SET @RowsDeleted = @@ROWCOUNT
    END
14 голосов
/ 26 января 2010

Если в вашей таблице столько записей и вы хотите удалить их все, вам следует рассмотреть truncate <table> вместо delete from <table>. Это будет намного быстрее, но имейте в виду, что он не может активировать триггер.

См. Более подробную информацию (в данном случае SQL Server 2000): http://msdn.microsoft.com/en-us/library/aa260621%28SQL.80%29.aspx

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

3 голосов
/ 26 января 2010

Вариант 1 создаст очень большую транзакцию и окажет большое влияние на журнал / производительность, а также увеличит количество блокировок, так что таблица будет недоступна. Вариант 2 будет медленнее, хотя он будет оказывать меньшее влияние на журнал (при условии объемного / полного режима)

Если вы хотите избавиться от всех данных, Truncate Table MyTable будет быстрее, чем оба, хотя он не имеет средств для фильтрации строк, он выполняет изменение метаданных сзади и в основном отбрасывает IAM на полу для таблица, о которой идет речь.

3 голосов
/ 26 января 2010

Первый имеет явно лучшую производительность.

Когда вы укажете DELETE [MyTable], он просто сотрет все без проверки идентификатора. Второй будет тратить время и дисковые операции, чтобы найти соответствующую запись каждый раз перед ее удалением.

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

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

2 голосов
/ 26 января 2010

Лучшая производительность для очистки таблицы принесет TRUNCATE TABLE MyTable. См. http://msdn.microsoft.com/en-us/library/ms177570.aspx для более подробного объяснения

0 голосов
/ 04 сентября 2014

Нашел эту запись в Microsoft TechNet .

В основном, он рекомендует:

  1. С помощью SELECT INTO скопируйте данные, которые вы хотите сохранить, в промежуточную таблицу;
  2. Обрезать исходную таблицу;
  3. Скопировать обратно с помощью INSERT INTO из промежуточной таблицы, данные в исходную таблицу;

..

BEGIN TRANSACTION

SELECT  *
   INTO    dbo.bigtable_intermediate
   FROM    dbo.bigtable
   WHERE   Id % 2 = 0;

   TRUNCATE TABLE dbo.bigtable;  

   SET IDENTITY_INSERT dbo.bigTable ON;
   INSERT INTO dbo.bigtable WITH (TABLOCK) (Id, c1, c2, c3)
   SELECT Id, c1, c2, c3 FROM dbo.bigtable_intermediate ORDER BY Id;
   SET IDENTITY_INSERT dbo.bigtable OFF;
ROLLBACK TRANSACTION
0 голосов
/ 26 января 2010

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

Теперь, если вам нужно удалить все данные из таблицы и вы не полагаетесь на использование отката, подумайте об использовании усеченной таблицы

...