如何在linq中有效地加入字符串?

时间:2016-05-09 13:36:08

标签: c# linq

我在linq中有一个很大的连接语句,执行时间太长(超过2分钟)。我按照它的方式尝试查看数据库是否设置正确并且我正确地获取数据,但现在项目几乎完成,这种延迟是不可接受的。

问题显然是String.Join语句,但我不知道如何以另一种方式做到这一点,所以我的问题是如何修改链接语句以获取相同的信息,但是更快捷的方式。我曾经想过,加入数据并将其存储在创建其中一个需要加入的实体的其他地方可能会更好,但如果可能的话,最好让这个声明更好。

ProjectQueryElement可能没有" b"的功能的组件。或" m"等

var dc = datacontext;
var resultSet = (
    from r in dc.requests
    select new ProjectQueryElement {
        bKey = String.Join( "|", dc.comps
                    .Where(
                        x => x.reRequestId == r.requestId && x.function == "b"
                    ).Select( x => x.idNumber )
               ),
        mKey = String.Join( "|", dc.comps
                    .Where(
                        x => x.reRequestId == r.requestId && x.function == "m"
                    ).Select( x => x.idNumber )
               ),
        oKey = String.Join( "|", dc.comps
                    .Where(
                        x => x.reRequestId == r.requestId && x.function == "o"
                    ).Select( x => x.idNumber )
               ),
        pKey = String.Join( "|", dc.comps
                    .Where(
                        x => x.reRequestId == r.requestId && x.function == "p"
                    ).Select( x => x.idNumber )
               ),
        rKey = String.Join( "|", dc.comps
                    .Where(
                        x => x.reRequestId == r.requestId && x.function == "r"
                    ).Select( x => x.idNumber )
               )
       }
);

resultSet将作为网格的行传递给jqgrid

2 个答案:

答案 0 :(得分:2)

  

问题显然是String.Join陈述

我怀疑String.Join是瓶颈,而是传递给该方法调用的子查询。

假设您有N个请求和M5 * N * M个请求。在LINQ to Objects中,您的查询将执行5 * N线性搜索。数据库可查询提供程序已翻译的SQL查询将执行AsEnumerable()子查询,如果没有适当的索引,则生成的时间复杂度将类似于LINQ to Objects(由于全表扫描,时间更差)。

IMO最好将数据检索逻辑与数据转换逻辑分开。做原始数据关联(连接 - @Jon Skeet在评论中立即指出的东西)和投影(选择)在数据库内,然后在内存中进行数据转换(字符串转换/连接),最好按顺序处理数据库查询结果(ToList vs var resultSet = (from r in dc.requests join c in dc.comps on r.requestId equals c.reRequestId into requestComps select requestComps.Select(c => new { c.function, c.idNumber })) .AsEnumerable() .Select(requestComps => new ProjectQueryElement { bKey = string.Join("|", requestComps.Where(c => c.function == "b").Select(c => c.idNumber)), mKey = string.Join("|", requestComps.Where(c => c.function == "m").Select(c => c.idNumber)), oKey = string.Join("|", requestComps.Where(c => c.function == "o").Select(c => c.idNumber)), pKey = string.Join("|", requestComps.Where(c => c.function == "p").Select(c => c.idNumber)), rKey = string.Join("|", requestComps.Where(c => c.function == "r").Select(c => c.idNumber)), }); 和类似的)。

应用所有这些将导致类似这样的事情:

Select

此时IMO你应该有一个很好的快速运行查询。

现在,如果确实需要,您可以优化转换部分(最后string.Join)。 requestComps是内部优化的,因此唯一的优化可能是对var query = // ... .Select(requestComps => { StringBuilder bKey = null, mKey = null, oKey = null, pKey = null, rKey = null; foreach (var c in requestComps) { switch (c.function) { case "b": bKey = (bKey != null ? bKey.Append("|") : new StringBuilder()).Append(c.idNumber); break; case "m": mKey = (mKey != null ? mKey.Append("|") : new StringBuilder()).Append(c.idNumber); break; case "o": oKey = (oKey != null ? oKey.Append("|") : new StringBuilder()).Append(c.idNumber); break; case "p": pKey = (pKey != null ? pKey.Append("|") : new StringBuilder()).Append(c.idNumber); break; case "r": rKey = (rKey != null ? rKey.Append("|") : new StringBuilder()).Append(c.idNumber); break; } } return new ProjectQueryElement { bKey = bKey != null ? bKey.ToString() : string.Empty, mKey = mKey != null ? mKey.ToString() : string.Empty, oKey = oKey != null ? oKey.ToString() : string.Empty, pKey = pKey != null ? pKey.ToString() : string.Empty, rKey = rKey != null ? rKey.ToString() : string.Empty, }; }); 集进行单次传递,但由于它在内存中运行,我认为性能影响可以忽略不计。提供该部分只是为了完整性,以便您可以衡量和看到实际影响:

showFrame = function(url, id) {
  var iframe = document.querySelector(id);
  iframe.style.display = "block";
  iframe.src = url;
};

hideFrame = function(id) {
  var iframe = document.querySelector(id);
  iframe.style.display = "none";
  iframe.src = "";
};

toggleFrame = function(url, id) {
  var iframe = document.querySelector(id);
  if (iframe.style.display == 'none') {
    showFrame(url, id);
  } else if (iframe.src == url) {
    hideFrame(id);
  } else {
    showFrame(url, id);
  }
};

答案 1 :(得分:0)

由于您使用的是Linq,因此您只需使用Aggregate功能:

xKey = dc.comps
    .Where(x => x.reRequestId == r.requestId && x.function == "b")
    .Aggregate((result, next) => result + "|" + next.idNumber);