慢查询实体框架

时间:2014-02-13 11:34:49

标签: c# mysql sql entity-framework

我注意到我对实体框架的一个查询太慢了。我认为问题在于我使用的是包含,但我没有得到“任何”的速度差异。我正在进行此查询的表有大约4k条目,所以我无法理解为什么这需要20秒才能完成。我使用mysql与最新的.net连接器

var errorMessages = msgs.Where(m => m.Type == 1 && 
            (m.StatusCode == (int)ErrorCode.AbsentSubscriber || 
             m.StatusCode == (int)ErrorCode.AbsentSubscriber || 
             m.StatusCode == (int)ErrorCode.Deleted ||
             m.StatusCode == (int)ErrorCode.Error ||
             m.StatusCode == (int)ErrorCode.Expired ||
             m.StatusCode == (int)ErrorCode.InvalidDestination ||
             m.StatusCode == (int)ErrorCode.Rejected ||
             m.StatusCode == (int)ErrorCode.SubscriberError ||
             m.StatusCode == (int)ErrorCode.Undeliverable ||
             m.StatusCode == (int)ErrorCode.UnknownSubscriber))
            .GroupBy(m => m.StatusCode);

foreach (var error in errorMessages)
{
    var eSum =
            db.ErrorSumMessages.SingleOrDefault(
                m => m.ErrorCode == error.Key 
                && m.MessagesId == oldHourlyMessage.MessagesId);

    if (eSum != null)
    {
        //This gets called
        eSum.Count += error.Sum(m => m.MessageCount);
        db.Entry(eSum).Property(m => m.Count).IsModified = true;
    }
    else
    {
        db.ErrorSumMessages.Add(new ErrorSumMessage
            {
                Count = error.Sum(m => m.MessageCount),
                ErrorCode = error.Key,
                ErrorText = error.First().StatusText,
                MessagesId = oldHourlyMessage.MessagesId
            });
    } 
}

2 个答案:

答案 0 :(得分:2)

在您的代码中,在每次迭代中称为db query - db.ErrorSumMessages.SingleOrDefault。如果errorMessages包含4K记录,则会获得4K查询!

要减少数据库查询的数量,请在foreach语句之前选择所需的(或全部)db.ErrorSumMessages:

var localErrorSumMessages = db.ErrorSumMessages.ToList();
foreach (var error in errorMessages)
{
   var eSum = localErrorSumMessages.SingleOrDefault(....); // selecting from collection in memory

答案 1 :(得分:1)

确保您还查询主查询中的ErrorSumMessages

var errorMessages = msgs.Where(...)
            .GroupBy(m => m.StatusCode)
            .Select(g => new 
                 { 
                   StatusCode = g.Key,
                   eSum = db.ErrorSumMessages
                            .FirstOrDefault(
                            m => m.ErrorCode == g.Key 
                              && m.MessagesId == oldHourlyMessage.MessagesId),
                   Messages = g
                 })

foreach(var row in errorMessages)
{
    var eSum = row.eSum;
    var error = row.Messages;
    // rest should work unaltered, except error.Key => row.StatusCode
    ...

}

你必须使用FirstOrDefault否则EF将抛出“方法'单'和'单一默认'只能用作最终查询操作”。