字符串连接优化

时间:2011-01-20 09:28:53

标签: c# sql mysql optimization

我们目前正在使用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')

现在在这种特殊情况下,我们需要返回50,000行..这是通过5个单独的查询生成的,分割负载。 数据库返回相当快(几秒钟内),但生成查询需要时间。

这是调用生成此特定查询的最后一个函数:

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 个答案:

答案 0 :(得分:5)

您的聚合代码基本上是循环中的字符串连接。不要那样做。

选项:

  1. 使用StringBuilder
  2. 使用string.Join

答案 1 :(得分:2)

以下是使用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

答案 2 :(得分:1)

我没有制作测试用例并对您的代码进行了描述,因此我不知道您可以期待多少改进。

使用StringBuilder而不是String.Format和+ =运算符。已知+ =运算符很慢。我怀疑String.Format也会有点慢。

您也可以尝试使用string.Join而不是手动加入数组。它适用于较新版本的.NET框架(4.0?)中的IEnumerable。

答案 3 :(得分:0)

不确定你为什么要做list.Cast当一个普通的IEnumerable无论如何都是对象。但是您的整个ListToDBList可以替换为

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

不确定会有多快,但我的想法更清楚。