Удаление большого количества записей занимает ОЧЕНЬ много времени

У меня есть таблица базы данных (работающая на SQL Server 2012 Express), содержащая ~ 60 000 строк.

Я использую следующий код для очистки старых строк:

//Deleting CPU measurements older than (oldestAllowedTime)
var allCpuMeasurementsQuery = from curr in msdc.CpuMeasurements where 
    curr.Timestamp < oldestAllowedTime select curr;
foreach (var cpuMeasurement in allCpuMeasurementsQuery)
{
  msdc.CpuMeasurements.Remove(cpuMeasurement);
}

Когда количество удаленных строк велико (удаляется ~ 90% или более записей в таблицах) операция занимает исключительно много времени. Для завершения этой операции на относительно мощной машине (настольный компьютер Intel I5) требуется около 30 минут.

  1. это кажется нормальным поведением?

  2. есть идеи о том, что я могу сделать, чтобы сократить время операции?

Спасибо,


person OSH    schedule 08.05.2013    source источник
comment
Посмотрите на DeleteAllOnSubmit, может поможет.   -  person DavidB    schedule 08.05.2013
comment
AFAIK то, что вы делаете, запускает более 60000 команд удаления из базы данных. Если бы вы могли вместо этого запускать только одну команду или партии из нескольких сотен команд или меньше, у вас не было бы такой проблемы с производительностью.   -  person Geeky Guy    schedule 08.05.2013
comment
Entity Framework не очень хорош в таких вещах. Возможно, лучше всего создать хранимую процедуру, которую вы передаете в метке времени, и таким образом удаляет все записи.   -  person Belogix    schedule 08.05.2013
comment
Обычно я заключаю их в одну транзакцию. Если это не улучшит ситуацию, я вызову SPROC для выполнения работы, поскольку это позволит избежать большого сетевого трафика.   -  person itsmatt    schedule 08.05.2013
comment
Я второй Белогикс. Фреймворк Entity не очень хорош и обрабатывает большое количество записей в лучшие времена. Я бы написал SP, чтобы справиться с этим, или выполнил бы запрос.   -  person Simon    schedule 08.05.2013
comment
Кроме того, есть ли у вас указатель в столбце Timestamp?   -  person itsmatt    schedule 08.05.2013
comment
Какие попытки оптимизации этого запроса вы предпринимали? Вы думали о том, чтобы запустить этот запрос по сегментам?   -  person Security Hound    schedule 08.05.2013
comment
Что это за база данных?   -  person RBarryYoung    schedule 08.05.2013
comment
@itsmatt Ой. Мне стыдно сказать, что метка времени не является индексом в таблице. Я сейчас встану в угол ...   -  person OSH    schedule 08.05.2013


Ответы (4)


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

var deleteOld = "DELETE FROM CpuMeasurements WHERE curr.Timestamp < {0}";
msdc.ExecuteStoreCommand(deleteOld, oldestAllowedTime);

При этом вам не нужно загружать объекты в память (просто для их удаления) и выдавать тысячи команд удаления в базу данных.

person Magnus    schedule 08.05.2013
comment
Я ценю все предложения здесь. Я пока выбираю это решение, так как оно кажется самым простым (по крайней мере, мне). Я действительно думаю, что другие упомянутые здесь решения кажутся многообещающими (EntityFramework.Extended), и я проверю их, когда все уляжется. - person OSH; 08.05.2013

Вам следует взглянуть на EntityFramework.Extended, он был создан для помощи как при массовом удалении, так и при обновлении.

Используя его, вы могли просто:

msdc.CpuMeasurements.Delete(curr => curr.Timestamp < oldestAllowedTime);
person mattytommo    schedule 08.05.2013

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

EntityFramework.extended может справиться с этим сценарием.

person Kenneth    schedule 08.05.2013

Удаление огромных объемов данных может занять много времени.

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

person Joe Ratzer    schedule 08.05.2013