Удаление большого объема данных в sql server

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

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

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

    DELETE FROM MyTable WHERE ID = @SelectedID
    

первое решение имеет лучшую производительность? каково влияние на журнал и производительность?

7 ответов


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

дополнительные сведения см. В разделе (в данном случае sql server 2000): http://msdn.microsoft.com/en-us/library/aa260621%28SQL.80%29.aspx

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


Если вам нужно ограничить, какие строки вам нужно удалить, а не сделать полное удаление, или вы не можете использовать усеченную таблицу (например, таблица ссылается на ограничение 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 сбросит значение идентификатора для таблицы, если оно есть.

Если вы не при использовании 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

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

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

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

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


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

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


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


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

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


нашел это сообщение на 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