C # Эффективно удалить 50000 записей в пакетах, используя SQLBulkCopy или эквивалентную библиотеку - PullRequest
0 голосов
/ 28 января 2019

Я использую эту библиотеку для массового удаления в пакетах, как показано ниже:

  while (castedEndedItems.Any())
  {
    var subList = castedEndedItems.Take(4000).ToList();
    DBRetry.Do(() => EFBatchOperation.For(ctx, ctx.SearchedUserItems).Where(r => subList.Any(a => a == r.ItemID)).Delete(), TimeSpan.FromSeconds(2));
    castedEndedItems.RemoveRange(0, subList.Count);
    Console.WriteLine("Completed a batch of ended items");
  }

Как вы видите, ребята, я беру серию из 4000 элементов для удаления сразу и передаю их в качестве аргументазапрос ...

Я использую эту библиотеку для массового удаления:

https://github.com/MikaelEliasson/EntityFramework.Utilities

Однако такая производительность абсолютно ужасна ... Я тестировал приложение пару раз инапример, для удаления 80000 записей требуется буквально 40 минут !?

Следует отметить, что этот параметр, по которому я удаляю (ItemID), относится к типу varchar (400) и индексируется по соображениям производительности ....

Есть ли какая-либо другая библиотека, котораяЯ мог бы использовать или настроить этот запрос, чтобы он работал быстрее, потому что в настоящее время производительность абсолютно ужасна ..: /

Ответы [ 3 ]

0 голосов
/ 28 января 2019

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

using(var cmd = db.CreateCommand())
{
    int index = 0;
    var sql = new StringBuilder("delete from [SomeTable] where [SomeId] in (");
    foreach(var item in items)
    {
        if (index != 0) sql.Append(',');
        var name = "@id_" + index++;
        sql.Append(name);
        cmd.Parameters.AddWithValue(name, item.SomeId);            
    }
    cmd.CommandText = sql.Append(");").ToString();
    cmd.ExecuteNonQuery();
}

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

0 голосов
/ 28 января 2019

Если вы не возражаете против дополнительной зависимости, вы можете использовать пакет NuGet Z.EntityFramework.Plus.

Код примерно такой:

using Z.EntityFramework.Plus;
[...]
         using (yourDbContext context = new yourDbContext())
         {
              yourDbContext.yourDbSet.Where( yourWhereExpression ).Delete();
         }

Это простои эффективный.Документация содержит точные цифры о производительности.

Относительно лицензирования: Насколько мне известно, версия 1.8 имеет лицензию MIT: https://github.com/zzzprojects/EntityFramework-Plus/blob/master/LICENSE Более новая версия не бесплатна дляиспользовать.

0 голосов
/ 28 января 2019

Если вы готовы использовать хранимую процедуру, то вы можете сделать это без какой-либо внешней библиотеки:

  • Создайте sproc с помощью табличного параметра @ids
  • ОпределитеТип SQL для этого табличного параметра (просто столбец id в предположении простого PK)
  • В sproc используйте

    delete from table where id in (select id from @ids);
    
  • В вашем приложениисоздать DataTable и заполнить в соответствии с таблицей SQL

  • Передать таблицу данных в качестве параметра команды при вызове sproc.

Этот ответ иллюстрирует процесс.

Любой другой вариант должен будет сделать эквивалент этого - или что-то менее эффективное.

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