Удаление данных из большой таблицы - PullRequest
5 голосов
/ 13 мая 2009

У меня есть таблица с 10 полями для хранения информации GPS для клиентов. Со временем, когда мы добавили больше клиентов, эта таблица выросла до 14 миллионов строк. По мере поступления данных gps служба постоянно вставляет строку в таблицу. 90% данных не являются откровенными, т. Е. Клиенту все равно, где автомобиль находился 3 месяца назад, но самые последние данные используются для создания отчетов об отслеживании. Моя цель - написать sql для очистки данных старше месяца.

Вот моя проблема, я не могу использовать TRUNCATE TABLE, так как я бы все потерял? Вчера я написал оператор удаления таблицы с предложением where. Когда я запустил его в тестовой системе, он заблокировал мою таблицу, и симуляторы gps периодически терпели неудачу. Кроме того, мой журнал транзакций вырос до 6 ГБ, поскольку он пытался регистрировать каждое удаление.

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

Ответы [ 15 ]

10 голосов
/ 13 мая 2009

Мои 2 цента:

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

Возможно, если вы в состоянии принимать решения dba, вы можете временно изменить свою модель журнала на Simple, чтобы она не росла слишком быстро, она все равно будет расти, но журнал не будет слишком подробным .

4 голосов
/ 13 мая 2009

Попробуйте это

WHILE EXISTS (SELECT * FROM table WHERE (условие для удаления))

НАЧАТЬ
SET ROWCOUNT 1000
DELETE Table WHERE (условие для удаления)
УСТАНАВЛИВАЙТЕ ROWCOUNT 0
* 1011 КОНЕЦ *

Это удалит строки в группах по 1000

4 голосов
/ 13 мая 2009

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

Синтаксис Oracle (аналог SQL Server)

create table keep as select * from source where data_is_good = 1;
truncate table source;
insert into source select * from keep;

Вам нужно будет отключить внешние ключи, если они есть в исходной таблице.

В Oracle имена индексов должны быть уникальными во всей схеме, а не только для каждой таблицы. В SQL-сервере вы можете дополнительно оптимизировать это, просто переименовав «keep» в «source», так как вы можете легко создавать индексы с одинаковыми именами для обеих таблиц

3 голосов
/ 13 мая 2009

Если вы используете SQL Server 2005 или 2008, разделение с раздвижными окнами - это идеальное решение для этого - мгновенное архивирование или очистка без заметной блокировки. Посмотрите здесь для получения дополнительной информации.

2 голосов
/ 13 мая 2009

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

  • Фактическое приложение, только с текущими данными.

  • История.

Вам нужно написать небольшую работу "ETL", чтобы переместить данные из текущей в историю и удалить перемещенную историю.

Вам нужно периодически запускать это. Ежедневно - еженедельно - ежемесячно ежеквартально - технически не имеет значения. Важно то, что использует история и кто ее использует.

2 голосов
/ 13 мая 2009

Я бы сделал ручное удаление по дням / месяцам (какой бы ни была самая большая единица, с которой вы можете справиться.) Как только вы сделаете это первым, то напишите сохраненный процесс, который будет запускаться каждый день, который удаляет самые старые данные, которые вы не делаете не нужно.

DELETE FROM TABLENAME 
WHERE datediff(day,tableDateTime,getdate() > 90

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

2 голосов
/ 13 мая 2009

Можете ли вы скопировать последние данные в новую таблицу, обрезать таблицу, а затем скопировать ее обратно?

Конечно, тогда вам придется беспокоиться о том, чтобы сделать это снова через 6 месяцев или год.

1 голос
/ 13 мая 2009

Полагаю, вы не можете выключить производственную систему (или поставить в очередь результаты GPS для вставки после завершения очистки).

Я бы согласился с тем, что вы склонны удалять его часть за раз (возможно, 10%) в зависимости от производительности, которую вы найдете в своей тестовой системе.

Ваша таблица проиндексирована? Это могло бы помочь, но процесс индексации может иметь одинаковые эффекты для системы, как и одна большая чистка.

1 голос
/ 13 мая 2009

Я бы, наверное, сделал это партиями, как вы уже придумали. Другой вариант - вставить важные данные в другую таблицу, обрезать таблицу GPS, а затем снова вставить важные данные. У вас будет маленькое окно, в котором вы пропустите последние исторические данные. Насколько маленьким будет это окно, будет зависеть от того, сколько данных вам нужно переустановить. Кроме того, вам следует быть осторожным, если в таблице используются автоинкрементные числа или другие значения по умолчанию, чтобы использовать исходные значения.

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

0 голосов
/ 12 августа 2009

Чтобы журнал транзакций не выходил из-под контроля, измените его следующим образом:

DECLARE @i INT
SET @i = 1
SET ROWCOUNT 10000

WHILE @i > 0
BEGIN
    BEGIN TRAN
        DELETE TOP 1000 FROM dbo.SuperBigTable
        WHERE RowDate < '2009-01-01'
    COMMIT
    SELECT @i = @@ROWCOUNT
END
SET ROWCOUNT 0

А вот версия, использующая предпочтительный синтаксис TOP для SQL 2005 и 2008:

DECLARE @i INT
SET @i = 1

WHILE @i > 0
BEGIN
    BEGIN TRAN
        DELETE TOP 1000 FROM dbo.SuperBigTable
        WHERE RowDate < '2009-01-01'
    COMMIT
    SELECT @i = @@ROWCOUNT
END
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...