我们说我有一个复杂类型的列表(称为' ClientMessage')。 ClientMessage有一种名为' MsgText'以及名为' ClientMessageDeeplinkResponse'的班级列表除了一堆其他简单的类型之外。
目前,存储过程返回三个数据集。 tmpMsgResult是主要结果,tmpDeeplinkResult和tmpMsgTxt是次要结果,将用于丰富最终结果。
存储过程快速执行(sub second)。 tmpMsgResult返回26000行,tmpDeeplinkResult返回21000行,tmpMsgTxt返回63300行。
如何填充' MsgText'和' ClientMessageDeeplinkResponse'在ClientMessage中快速?我尝试了几种方法,从20秒到45秒。
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ItchyScratchy13
{
class CMCSimple
{
public static List<ClientMessage> ReadClientMessagesSP(string connString, string GCN, bool? messageDeleted, bool? messageArchived)
{
List<ClientMessage> results = new List<ClientMessage>();
using (SqlConnection conn = new SqlConnection(connString))
{
using (SqlCommand cmd = new SqlCommand("cmc.GetCmcMessages", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@GCN", SqlDbType.VarChar).Value = GCN;
cmd.Parameters.Add("@DeletedMsgs", SqlDbType.Bit).Value = messageDeleted;
cmd.Parameters.Add("@ArchivedMsgs", SqlDbType.Bit).Value = messageArchived;
conn.Open();
DataSet ds = new DataSet();
SqlDataAdapter adapter;
adapter = new SqlDataAdapter(cmd);
adapter.Fill(ds);
var tmpMsgResult = ds.Tables[0].AsEnumerable().Select(s => new ClientMessage
{
MsgID = s.Field<int>("MessageId"),
MsgAuditID = s.Field<int>("MessageAuditId"),
MsgGUID = s.Field<Guid>("MsgGuid"),
}).ToList();
var tmpDeeplinkResult = ds.Tables[1].AsEnumerable().Select(s => new AdminClientMessageDeeplink
{
MessageId = s.Field<int>("MessageId"),
DeeplinkMask = s.Field<string>("DeeplinkMask"),
DeeplinkName = s.Field<string>("DeeplinkName"),
DeepLinkValue = s.Field<string>("DeeplinkValue"),
}).ToList();
var tmpMsgTxt = ds.Tables[2].AsEnumerable().Select(s => new AdminClietnMsgTxt
{
MessageId = s.Field<int>("MessageId"),
MessageTxt = s.Field<string>("MessageText"),
RowNumber = int.Parse(s.Field<Int64>("ROW_NUMBER").ToString()),
}).ToList();
//ATTEMPT 1
Parallel.ForEach(tmpMsgResult, item =>
{
item.DeepLink = tmpDeeplinkResult.Where(wh => wh.MessageId == item.MsgID).Select(s => new ClientMessageDeeplinkResponse
{
DeeplinkMask = s.DeeplinkMask,
DeeplinkName = s.DeeplinkName,
DeepLinkValue = s.DeepLinkValue,
}).ToList();
item.MsgText = tmpMsgTxt.Where(wh => wh.MessageId == item.MsgID).Select(s => new KeyValuePair<int, string>(s.RowNumber, s.MessageTxt)).ToDictionary(x => x.Key, x => x.Value);
});
//ATTEMPT 2
results = tmpMsgResult.Select((x, i) => new ClientMessage
{
DeepLink = tmpDeeplinkResult.Where(wh => wh.MessageId == x.MsgID).AsParallel().Select(s => new ClientMessageDeeplinkResponse() { DeeplinkMask = s.DeeplinkMask, DeeplinkName = s.DeeplinkName, DeepLinkValue = s.DeepLinkValue }).ToList(),
MsgAuditID = x.MsgAuditID,
MsgGUID = x.MsgGUID,
MsgID = x.MsgID,
MsgText = tmpMsgTxt.Where(wh => wh.MessageId == x.MsgID).AsParallel().Select(s => new { s.RowNumber, s.MessageTxt }).ToDictionary(td => td.RowNumber, td => td.MessageTxt)
}).ToList();
//ATTEMPT 3
foreach (var item in tmpMsgResult)
{
item.DeepLink = tmpDeeplinkResult.Where(wh => wh.MessageId == item.MsgID).Select(s => new ClientMessageDeeplinkResponse
{
DeeplinkMask = s.DeeplinkMask,
DeeplinkName = s.DeeplinkName,
DeepLinkValue = s.DeepLinkValue
}).ToList();
item.MsgText = tmpMsgTxt.Where(wh => wh.MessageId == item.MsgID).Select(s => new KeyValuePair<int, string>(s.RowNumber, s.MessageTxt)).ToDictionary(x => x.Key, x => x.Value);
}
//ATTEMPT 4, super fast but not correct result set
results = (from zxc in tmpMsgResult
join vbn in tmpDeeplinkResult
on zxc.MsgID equals vbn.MessageId
join asd in tmpMsgTxt
on zxc.MsgID equals asd.MessageId
select new ClientMessage
{
DeepLink = new List<ClientMessageDeeplinkResponse>() { vbn },
MsgAuditID = zxc.MsgAuditID,
MsgGUID = zxc.MsgGUID,
MsgID = zxc.MsgID,
MsgText = new Dictionary<int, string> { { asd.RowNumber, asd.MessageTxt } }
}).ToList();
}
}
return results;
}
}
public class ClientMessage
{
public int MsgID { get; set; }
public int MsgAuditID { get; set; }
public Guid? MsgGUID { get; set; }
public Dictionary<int, string> MsgText { get; set; }
public List<ClientMessageDeeplinkResponse> DeepLink { get; set; }
}
public class AdminClientMessageDeeplink : ClientMessageDeeplinkResponse
{
public int MessageId { get; set; }
public int DeeplinkId { get; set; }
}
public class AdminClietnMsgTxt
{
public int MessageId { get; set; }
public string MessageTxt { get; set; }
public int RowNumber { get; set; }
}
public class ClientMessageDeeplinkResponse
{
public string DeeplinkName { get; set; }
public string DeepLinkValue { get; set; }
public string DeeplinkMask { get; set; }
}
}
答案 0 :(得分:1)
使用GroupBy
和Dictionaries
应该可以按照以下方式执行操作:
....
// It's better to use Dictionary for tmpDeeplinkResult and tmpMsgTxt
var grouppedTmpDeeplinkResult = tmpDeeplinkResult.GroupBy(x => x.MessageId).ToDictionary(g => g.Key, g => g.ToList());
var grouppedTmpMsgTxt = tmpDeeplinkResult.GroupBy(x => x.MessageId).ToDictionary(g => g.Key, g => g.ToDictionary(x => x.RowNumber, x => x.MessageTxt));
foreach (var item in tmpMsgResult)
{
item.DeepLink = grouppedTmpDeeplinkResult[item.MsgID].Select(s => new ClientMessageDeeplinkResponse
{
DeeplinkMask = s.DeeplinkMask,
DeeplinkName = s.DeeplinkName,
DeepLinkValue = s.DeepLinkValue
}).ToList();
item.MsgText = grouppedTmpMsgTxt[item.MsgID];
}
....
字典的查找(例如dict [x])可能看起来与List相同,但它使用hashset并且具有O(1)
复杂度,而list.Where(...)
具有O(N)
的复杂性。