2009-05-13 2 views
5

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

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

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

+2

Какой вкус базы данных вы используете? – BIBD

+0

MS SQL 2005 Standard –

ответ

4

Попробуйте

ПОКА СУЩЕСТВУЕТ (SELECT * FROM таблицы WHERE (условие для удаления))

НАЧАТЬ
SET ROWCOUNT 1000
DELETE Таблица WHERE (условие для удаления)
SET ROWCOUNT 0
ENd

Это удалит r ows в группах по 1000

+0

Помогла ли вам это сделать? – Eric

+1

Я бы добавил WAITFOR DELAY '00: 00: 04 'для избежания замки –

+0

Спасибо, это похоже на то, что я ищу. Сегодня я буду тестировать. –

2

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

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

4

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

синтаксис 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, вы можете дополнительно оптимизировать это, просто переименовывая «держать» до «источника», как вы можете легко создавать индексы одного и того же имени на обеих таблицах

+0

Если данные постоянно вставлены, он не может использовать переименование, так как он может потерять любые данные, вставленные между временем вставки и переименованием. Он мог бы заключить сделку, но это может привести к таймаутам. –

10

Мои 2 цента:

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

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

+0

Спасибо, я проверю это –

1

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

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

+0

. Я подумал об этом, и, посмотрев на другие ответы, я также вижу некоторые достоинства в этом подходе. Кроме того, это всего лишь данные позиции gps и отсутствие пары минут данных, возможно, не проблема, а для движущегося транспортного средства, это может быть проблемой. Мои клиенты - полиция, и с моей удачей в ту минуту, когда я останавливаю gps, они получат высокоскоростное преследование, которое они захотят воспроизвести, и у меня не будет данных для них! –

3

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

+0

Разделенные таблицы работают только на Enterprise Edition :( – dariol

1

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

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

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

+1

Да, я не могу взять систему и да, таблица указана правильно. –

2

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

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

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

+0

Я согласен, поэтому я тестирую это на не производственном сервере, поэтому, если все работает, я просто копирую sql. –

0

Имейте в виду, что большинство баз данных блокируют соседние записи в индексе во время транзакции, поэтому сохранение коротких операций будет полезным. Я предполагаю, что ваши вставки терпят неудачу в тайм-аутах ожидания блокировки, поэтому удаляйте свои данные в небольших, разобщенных транзакциях. Я бы предложил однопоточный Perl-скрипт, который прокручивается в течение старейших 1000 шагов порции. Я надеюсь, что ваш первичный ключ (и, надеюсь, кластеризованный индекс, если они каким-то образом оказались бы двумя разными способами), может быть соотнесен со временем, поскольку это было бы лучше всего удалить.

PseudoSQL: Выберите макс (Primid) < 3_months_ago Удалить из таблицы, где Primid < maxPrimId предел 1000

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

0

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

Это простой шаг - и не засоряют журналы и т.д. повторного выполнения

Там в основной интро ко всему этому here

2

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

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

  • История.

Вам нужно написать небольшое задание «ETL» для перемещения данных из текущего в историю и удаления перенесенной истории.

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

0

Включает ли оператор delete какой-либо из индексов в таблице? Зачастую огромное улучшение производительности может быть достигнуто либо путем изменения инструкции для использования существующего индекса, либо для добавления индекса в таблицу, который помогает повысить производительность запроса, который делает инструкция delete.

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

0

Производительность довольно быстро при отбрасывании стола - даже очень большой. Так вот что я буду делать. Создайте скрипт в своей таблице с индексами из Management Studio. Отредактируйте сценарий и запустите его, чтобы создать копию таблицы. Вызовите его table2. Сделайте вкладку выбора, чтобы запарковать данные, которые вы хотите сохранить, в новую таблицу2. Переименуйте старую таблицу, скажем, tableOld. Переименуйте таблицу2 с исходным именем. Подождите. Если никто не кричит, вы бросаете стол2. Существует определенный риск. 1) Проверьте, есть ли триггеры или ограничения, определенные в исходной таблице. Они не могут быть включены в скрипт, созданный студией управления. 2) если исходная таблица имеет поля идентификации, возможно, вам придется включить идентификатор_интеста перед вставкой в ​​новую таблицу.

0

Я придумал следующий скрипт T-SQL, который получает произвольное количество последних данных.

IF EXISTS(SELECT name FROM sys.tables WHERE name = 'tmp_xxx_tblGPSVehicleInfoLog') 
BEGIN 
    PRINT 'Dropping temp table tmp_xxx_tblGPSVehicleInfoLog' 
    DROP TABLE tmp_xxx_tblGPSVehicleInfoLog 
END 
GO 

PRINT 'Creating temp table tmp_xxx_tblGPSVehicleInfoLog' 
CREATE TABLE [dbo].[tmp_xxx_tblGPSVehicleInfoLog](
    [GPSVehicleInfoLogId] [uniqueidentifier] NOT NULL, 
    [GPSVehicleInfoId] [uniqueidentifier] NULL, 
    [Longitude] [float] NULL, 
    [Latitude] [float] NULL, 
    [GroundSpeed] [float] NULL, 
    [Altitude] [float] NULL, 
    [Heading] [float] NULL, 
    [GPSDeviceTimeStamp] [datetime] NULL, 
    [Milliseconds] [float] NULL, 
    [DistanceNext] [float] NULL, 
    [UpdateDate] [datetime] NULL, 
    [Stopped] [nvarchar](1) NULL, 
    [StopTime] [datetime] NULL, 
    [StartTime] [datetime] NULL, 
    [TimeStopped] [nvarchar](100) NULL 
) ON [PRIMARY] 
GO 

PRINT 'Inserting data from tblGPSVehicleInfoLog to tmp_xxx_tblGPSVehicleInfoLog' 
SELECT * INTO tmp_xxx_tblGPSVehicleInfoLog 
FROM tblGPSVehicleInfoLog 
WHERE tblGPSVehicleInfoLog.UpdateDate between '03/30/2009 23:59:59' and '05/19/2009 00:00:00' 
GO 

PRINT 'Truncating table tblGPSVehicleInfoLog' 
TRUNCATE TABLE tblGPSVehicleInfoLog 
GO 

PRINT 'Inserting data from tmp_xxx_tblGPSVehicleInfoLog to tblGPSVehicleInfoLog' 
INSERT INTO tblGPSVehicleInfoLog 
SELECT * FROM tmp_xxx_tblGPSVehicleInfoLog 
GO 
0

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

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 
Смежные вопросы