Оптимизация конкатенации строк - PullRequest
2 голосов
/ 20 января 2011

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

До сих пор все работало нормально;очень быстро, почти никаких проблем.Недавно мы столкнулись с проблемами эффективности при запросе большого количества данных из базы данных.

Мы строим запрос следующим образом:

var someIntList = new List<int> { 1,2,3,4,5 };
var query = dtx.Query.Containers.Where(c => c.ContainerID.IsIn(someIntList));

или

var someStringList = new List<int> {"a", "b", "c" };
query = dtx.Query.Containers.Where(c => c.BuildingName.IsIn(someStringList));

Который будет генерировать (вместе с кучей других вещей, не связанных с этим):

SELECT * FROM Container WHERE ContainerID IN (1,2,3,4,5)

и

SELECT * FROM Container WHERE BuildingName IN ('a','b','c')

Теперь в этой конкретной ситуации нам нужно вернуться50000 строк .. который генерируется через 5 отдельных запросов, разделяя нагрузку.DB возвращается довольно быстро (в течение нескольких секунд), однако генерация запроса занимает long time.

Вот самая последняя функция, которая вызывается для генерации этого конкретного запроса:

private static string GetSafeValueForItem(object item)
{
    if (item == null)
        return "NULL";

    if (item is bool)
        return ((bool)item ? "1" : "0");
    if (item is string)
        return string.Format("'{0}'", item.ToString().Replace("'", "''"));
    if (item is IEnumerable)
        return ListToDBList((IEnumerable)item);
    if (item is DateTime)
        return string.Format("'{0}'", ((DateTime)item).ToString("yyyy-MM-dd HH:mm:ss"));

    return item.ToString();
}

private static string ListToDBList(IEnumerable list)
{
    var str = list.Cast<object>().Aggregate("(", (current, item) => current + string.Format("{0},", GetSafeValueForItem(item)));
    str = str.Trim(',');
    str += ")";
    return str;
}

Есть ли какие-либо очевидные улучшения, которые могут быть сделаны для ускорения конкатенации строк в этом случае?Рефакторинг кода и использование другой реализации (например, избегания генерации запросов и непосредственного обращения к базе данных) не является предпочтительным, но если бы он обеспечил значительное повышение производительности, было бы здорово услышать.

Ответы [ 4 ]

5 голосов
/ 20 января 2011

Ваш Aggregate-код в основном представляет собой конкатенацию строк в цикле.Не делайте этого.

Опции:

  1. Использовать StringBuilder
  2. Использовать строку.
2 голосов
/ 20 января 2011

Вот пример использования String.Join, который выводит то же самое, что и ваш ListToDBList:

String.Format("({0})", String.Join(",", list.Cast<object>().Select(item=>GetSafeValueForItem(item)).ToArray()));

См. Здесь для объяснения, почему конкатенация в цикле с использованием + (что и делал ваш вызов Aggregate) медленная: http://www.yoda.arachsys.com/csharp/stringbuilder.html

1 голос
/ 20 января 2011

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

Используйте StringBuilder вместо String.Format и оператор + =.Оператор + = известен как медленный.Я подозреваю, что String.Format тоже будет несколько медленным.

Вы также можете попробовать string.Join вместо ручного присоединения к массиву.Он работает на IEnumerable в новых версиях .NET Framework (4.0?).

0 голосов
/ 20 января 2011

Не уверен, почему вы делаете list.Cast, когда обычный IEnumerable будет из объектов в любом случае.Но весь ваш ListToDBList можно заменить на

string.Format("({0})", string.Join(",",list.ToArray())); 

Не уверен, насколько быстрее это будет, но, на мой взгляд, он более понятен.

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