繁体   English   中英

如何在小组中划分LINQ查询以避免Timeout过期异常?

[英]How to divide a LINQ query in small group to avoid Timeout expired exception?

我有LINQ查询如下

HashSet<Guid> temp1 ; // Getting this value through another method

var Ids = temp1.Except((from temp2 in prodContext.Documents 
                        where temp1.Contains(temp2.id) 
                        select temp2.id)).ToList();   

这里, temp1有大约40k的值。 我有时会遇到超时错误,如何使用while或任何其他循环来划分此查询,以便它不会给我超时错误。 我尝试在连接字符串和数据库上下文中设置连接超时,但没有任何作用。

有任何建议请

这是可能是一个查询的异常操作之一,可以由应用程序而不是数据库在内存中更有效地执行。 而不是试图将您在集合中的所有id值发送到数据库,让它找到所有带有这些ID的项目,然后将它们全部发送给您,获取所有文档非常合理id并在应用程序方面过滤它们。

var documentIds = prodContext.Documents.Select(doc => doc.id);
var Ids = temp1.Except(documentIds).ToList();   

现在,根据你有多少文件,理论上可能会超时。 如果是,那么您需要对所有文档ID的获取进行分页。 您可以使用以下方法对任何查询进行分页,以避免一次性获取整个结果集:

public static IEnumerable<IEnumerable<T>> Paginate<T>(
    this IQueryable<T> query,
    int pageSize)
{
    int page = 0;
    while (true)
    {
        var nextPage = query.Skip(page * pageSize)
            .Take(pageSize)
            .ToList();
        if (nextPage.Any())
            yield return nextPage;
        else
            yield break;
        page++;
    }
}

这允许你写:

var documentIds = prodContext.Documents.Select(doc => doc.id)
    //play around with different batch sizes to see what works best
    .Paginate(someBatchSize)
    .SelectMany(x => x);
temp1.ExceptWith(documentIds);

这是一种结合分页和缓存的方法。

这样,它一次只缓存一个页面大小,以防止内存过载并防止超时。 我希望这有效。

int pageSize = 1000;

HashSet<Guid> temp1;

List<Guid> idsFromTable = new List<Guid>();

var Ids = temp1.ToList();
for(int i = 0; true; i++)
{
    //Cache the table locally to prevent logic running while selecting on page size
    idsFromTable.AddRange(prodContext.Documents.Skip(pageSize * i).Take(pageSize).Select(x=> x.id));

    if(idsFromTable.Any())
    {
        //Then use the cached list instead of the datacontext
        Ids = Ids.Except(idsFromTable).ToList();
        idsFromTable.Clear(); 
    }
    else
        break;
}

与Servy的回答类似,您可能希望尝试对查询进行分页,而不是仅仅将它们全部拉入。效率取决于您使用的数据库,我当然在Informix上获得了一些里程数。 在这种情况下,逻辑看起来像这样

HashSet<Guid> ids... //Got from another method
List<Guid> validIds = new List<Guid>();

const Int32 BUFFERSIZE = 1000;
var validationBuffer = new List<Guid>(BUFFERSIZE);

foreach(var g in ids)
{
    validationBuffer.Add(g)
    if(validationBuffer.Count == BUFFERSIZE)
    {
         validIds.AddRange(
             prodContext.Documents
                 .Select(t => t.id)
                 .Where(g => validationBuffer.Contains(g)));
         validationBuffer.Clear();
    }
}

//Do last query
validIds.AddRange(
    prodContext.Documents
        .Select(t => t.id)
        .Where(g => validationBuffer.Contains(g)));

var missingIds = ids.Except(validIds);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM