2015-04-05 6 views
-1

Я сбрасываю таблицу из MySQL в объект DataTable, используя MySqlDataAdapter. Ввод и вывод базы данных преуспевают, но мой код приложения, похоже, имеет проблему с производительностью, которую я смог отслеживать для конкретного оператора LINQ.Медленная производительность LINQ в DataTable Where Clause?

Цель проста, найти содержимое DataTable для значения столбца, соответствующего конкретной строке, точно так же, как и традиционное предложение SQL WHERE column = 'text'.

упрощенный код:

foreach (String someValue in someList) { 
    String searchCode = OutOfScopeFunction(someValue); 
    var results = emoteTable.AsEnumerable() 
     .Where(myRow => myRow.Field<String>("code") == searchCode) 
     .Take(1); 
    if (results.Any()) { 
     results.First()["columnname"] = 10; 
    } 
} 

Этот упрощенный код исполняется тысячи раз, один раз для каждой записи в someList. Когда я запускаю Visual Studio Performance Profiler, я вижу, что строка «results.Any()» подсвечивается как потребляющая 93,5% времени выполнения.

Я пробовал несколько различных методов для оптимизации этого кода, но ни один из них не улучшил производительность, сохранив в качестве основного источника данных DataTable emoteTable. Я могу преобразовать emoteTable в Dictionary<String, DataRow> за пределы foreach, но тогда мне нужно синхронизировать DataTable и словарь, который, хотя и улучшает производительность, чувствует себя не так.

Три вопроса:

  1. Является ли это правильный способ поиска значения в DataTable (эквивалент традиционной SQL предложения WHERE)? Если нет, то как СЛЕДУЕТ это сделать?
  2. Добавление к 1, независимо от правильного пути, что является самым быстрым (время выполнения)?
  3. Почему линия results.Any() потребляет 90% + ресурсов? В этой ситуации имеет смысл, что линия var results должна потреблять ресурсы, ведь линия - это фактический поиск, верно?

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

+0

Почему вы используете .Where(). Возьмите (1), а затем результаты.Any()? Почему не 'var result = emoteTable.AsEnumerable(). FirstOrDefault (myRow => myRow.Field (" code ") == searchCode)'? Тогда вы можете просто проверить, является ли результат нулевым. – john

ответ

0

Any() занимает 90% времени, поскольку result является only executed when you callAny(). Прежде чем позвонить Any(), запрос фактически не выполняется.

Казалось бы, проблема в том, что вы сначала извлечете всю таблицу в память и затем выполните поиск. Вы должны указать свою базу данных для поиска.
Кроме того, когда вы звоните results.First(), запрос results выполняется снова.

с отсрочкой исполнения в виду, вы должны написать что-то вроде

var result = emoteTable.AsEnumerable() 
    .Where(myRow => myRow.Field<String>("code") == searchCode) 
    .FirstOrDefault(); 

if (result != null) { 
    result["columnname"] = 10; 
} 
+0

Возможно, я неправильно использую конструкции DataTable и DataAdapter. Я думал, что цель этих классов состояла в том, чтобы позволить более быстрое взаимодействие с данными на стороне клиента, а затем вносить изменения в объемную нагрузку в базу данных. Мой рассматриваемый код вытаскивает таблицу, сравнивает ее с локальными данными, так как обнаруживает различия, которые он обновляет «DataTable», когда он заканчивается, он подталкивает изменения к базе данных (через «DataAdapter»). Есть ли лучший способ сделать это? –

+0

Я считаю, что «более быстрая» часть исходит из того, что это конструкции нижнего уровня и, следовательно, имеют меньше накладных расходов, хотя это может быть очень мало. Я не могу сказать, каким образом было бы лучше для вашей конкретной цели, вы должны попробовать пару и посмотреть (например, Linq2Sql контекст данных с 'SubmitChanges()', хранимую процедуру в MySQL, прямой запрос в цикле). Это нормально, если вы придерживаетесь своего нынешнего подхода, просто убедитесь, что вы понимаете концепцию отложенного исполнения Linq. – GSerg

0

Что вы реализовали в значительной степени присоединиться:

var searchCodes = someList.Select(OutOfScopeFunction); 
var emotes = emoteTable.AsEnumerable(); 

var results = Enumerable.Join(emotes, searchCodes, e=>e, sc=>sc.Field<String>("code"), (e, sc)=>sc); 

foreach(var result in results) 
{ 
    result["columnname"] = 10; 
} 

Присоединяйтесь, вероятно, оптимизировать доступ к обоим спискам с помощью какой-то поиска.

Но первое, что я хотел бы сделать, это полностью отказаться от идеи объединения DataTable и LINQ. Это две разные технологии и пытаются утверждать, что они могут делать внутри, когда они сложны.

Вы пытались выполнить необработанные вызовы UPDATE? Сколько элементов вы планируете обновлять?

+0

Я изначально выполнял необработанные запросы на обновление, и производительность была ОК, за исключением того факта, что я выполнял БОЛЬШОЕ число из них. Мне показалось, что я могу скопировать таблицу в память через DataAdapter/DataTable и внести изменения в DataTable, а затем синхронизировать ее с сервером. Возможно, моя архитектура испорчена. Я открыт для идей, где у вас есть буксировочный стол ~ 10k, который вам понадобится, чтобы внести тысячи изменений (обновление разных строк). –