2017-02-08 4 views
1

Я хочу удалить 10GB (1%) данных из таблицы 1TB. Я столкнулся с несколькими статьями, чтобы удалить большие объемы данных из огромной таблицы, но не нашел много информации об удалении меньшего процента данных из огромной таблицы.Как эффективно удалить небольшой набор данных из большой таблицы sql

Дополнительная информация: Пытается удалить данные бота из таблицы посещений. Условие фильтра представляет собой комбинацию полей ... внутрибрюшинно в (список изобр около 20 из них) и UserAgent, как «%»% ЧТО-ТО

размер UserAgent 1024 VARCHAR

Данные могут быть старым или новым. Я не могу использовать фильтр даты

+2

Возможно использование определенного фильтра. Объясните больше как то, что вы пытаетесь сделать. – Rahul

+0

Такая же концепция. Удалите его партиями. –

+0

Как @Rahul говорят, что до тех пор, пока поле условия имеет индекс, вы должны быть в порядке. В противном случае сообщите нам, что вы попробовали и в чем проблема. –

ответ

1

Вот пакетное удаление в кусках, которые я использую регулярно. Возможно, это даст вам некоторые идеи о том, как подойти к вашей потребности. Я создаю хранимую процедуру и вызываю proc из SQL Agent Job. Обычно я планирую его разрешить резервное копирование журнала транзакций между выполнением, поэтому журнал не становится слишком большим. Вы всегда можете просто запустить его в интерактивном режиме, если хотите.

SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 


CREATE PROC [DBA_Delete_YourTableName] AS 



SET NOCOUNT ON; 
--------------------------------------------------------- 
DECLARE @DaysHistoryToKeep INT 
SET @DaysHistoryToKeep = 90 

IF @DaysHistoryToKeep < 30 
SET @DaysHistoryToKeep = 30 
--------------------------------------------------------- 

DECLARE @continue INT 
DECLARE @rowcount INT 
DECLARE @loopCount INT 
DECLARE @MaxLoops INT 

DECLARE @TotalRows BIGINT 
DECLARE @PurgeThruDate DATETIME 

SET @PurgeThruDate = DATEADD(dd,(-1)*(@DaysHistoryToKeep+1), GETDATE()) 

SET @MaxLoops = 100 
SET @continue = 1 
SET @loopCount = 0 

SELECT @TotalRows = (SELECT COUNT(*) FROM YourTableName (NOLOCK) WHERE CREATEDDATETIME < @PurgeThruDate) 
PRINT 'Total Rows = ' + CAST(@TotalRows AS VARCHAR(20)) 
PRINT '' 

WHILE @continue = 1 
BEGIN 
    SET @loopCount = @loopCount + 1 
    PRINT 'Loop # ' + CAST(@loopCount AS VARCHAR(10)) 
    PRINT CONVERT(VARCHAR(20), GETDATE(), 120) 

    BEGIN TRANSACTION 
     DELETE TOP (4500) YourTableName WHERE CREATEDDATETIME < @PurgeThruDate 
     SET @rowcount = @@rowcount 
    COMMIT 

    PRINT 'Rows Deleted: ' + CAST(@rowcount AS VARCHAR(10)) 
    PRINT CONVERT(VARCHAR(20), GETDATE(), 120) 
    PRINT '' 

    IF @rowcount = 0 OR @loopCount >= @MaxLoops 
    BEGIN 
     SET @continue = 0 
    END 
END 

SELECT @TotalRows = (SELECT COUNT(*) FROM YourTableName (NOLOCK) WHERE CREATEDDATETIME < @PurgeThruDate) 
PRINT 'Total Rows Remaining = ' + CAST(@TotalRows AS VARCHAR(20)) 
PRINT '' 


GO 
1

условие фильтра ... внутрибрюшинно в (список изобр около 20 из них) и UserAgent, как «%»% ЧТО-ТО

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

  1. Я представляю на столе, который определяет размер вас уже есть индекс на столбце ip. Это может помочь (или нет) разместить ваш список 20 или около того ips в таблице, а не в предложении in, особенно если это параметры. Я бы посмотрел на мой план запросов.

  2. Я надеюсь, что useragent like '%SOMETHING%' обычно верно; в противном случае это дорогостоящий тест, потому что SQL Server должен проверять каждую строку для подходящего ip. Если нет, редизайн, позволяющий избежать запроса like, вероятно, будет полезен.

[D] eleting меньший процент не очень актуальна. Использование критериев выборочного поиска (согласно выше), равно как и размер транзакции удаления в абсолютных условиях. По определению размер удаления в терминах строк и размера строки определяет размер транзакции. Очень большие транзакции могут подталкивать к машинным ресурсам. Разбивка их на более мелкие может привести к повышению производительности в таких случаях.

Последний сервер, который я использовал, имел 0,25 ТБ оперативной памяти и был удобен удалять 1 миллион строк за раз, но не 10 миллионов. Ваше milage будет разным; вы должны попробовать и наблюдать, чтобы видеть.

Насколько вы готовы платить налоги от машины, будет зависеть от того, что еще (или должно быть в состоянии) работать одновременно. То, как вы разбиваете одно логическое действие - удалите все строки, где [условие] - в «куски» также зависит от того, что вы хотите, чтобы база данных выглядела, когда процедура удаления находится в процессе, когда некоторые куски удалены, а другие остаются настоящее время.

Если вы решили разбить его на куски, я рекомендую не используя фиксированное количество строк и синтаксис TOP(n), потому что это наименее логичная решения. Если вы не используете order by, вы уходите на сервер, чтобы выбрать произвольно, какие N строк для удаления. Если вы используете order by, вам требуется, чтобы сервер сортировал результат перед запуском удаления, возможно, несколько раз за весь прогон. BLEH!

Вместо этого найдите некоторое логическое подмножество строк, идеально различимое по кластерному индексу, которое подпадает под порог вашего компьютера из допустимого количества строк для удаления за один раз. Переверните этот набор. В вашем случае у меня возникнет соблазн повторить набор значений ip в предложении in. Вместо delete ... where ip in(...) вы получаете (примерно) for each ip delete ... where ip = @ip

Преимущество последнего подхода заключается в том, что вы всегда знаете, где находится база данных. Если вы убьете эту процедуру или она будет отброшена частично через свою итерацию, вы можете проверить базу данных, чтобы увидеть, какие ips все еще остаются (или любые критерии, которые вы в конечном итоге используете). Вы избегаете какого-либо патологического поведения, в результате чего некоторый запрос получает частичный результат, потому что какая-то часть ваших критериев выбора (определенная только сервером) присутствует, а другие удалены. В мышлении о проблеме вы можете сказать: Я не могу удалить ip 192.168.0.1, потому что, не задаваясь вопросом, какая часть уже удалена.

В общем, я рекомендую:

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