繁体   English   中英

使用for循环和linq查询增强性能

[英]Enhance performance with for loop and linq query

我有一个对象数组,我需要根据某些参数从数据库中获取一些对象信息,我正在实现此目的:

public IList<object[]> GetRelevants(Registro[] records)
    {
        List<object[]> returnList = new List<object[]>();
        using (var session = SessionFactory.OpenStatelessSession())
        {
            for (int kr = 0; kr < records.Length; kr++)
            {
                Registro record = records[kr];
                var query = session.QueryOver<Registro>()
                                    .Where(sb => sb.Asunto == record.Asunto)
                                    .And(sb => sb.FechaInicial == record.FechaInicial)
                                    .And(sb => sb.FechaFinal == record.FechaFinal)
                                    .And(sb => sb.FoliosDesde == record.FoliosDesde)
                                    .And(sb => sb.FoliosHasta == record.FoliosHasta)
                                    .And(sb => sb.TomoNumero == record.TomoNumero)
                                    .And(sb => sb.TomoTotal == record.TomoTotal)
                                    .And(sb => sb.SerieCodigo == record.SerieCodigo)
                                    .And(sb => sb.Caja == record.Caja)
                                    .And(sb => sb.Carpeta == record.Carpeta).SelectList(list => list
                                      .Select(p => p.Id)
                                      .Select(p => p.NuevaCaja)
                                      .Select(p => p.NuevaCarpeta)
                                      .Select(p => p.Periodo));

                var result = query.SingleOrDefault<object[]>();
                returnList.Add(result);
            }
        }
        return returnList;
    }

但是,在记录中,有超过10000个项目,因此NHibernate大约需要10分钟才能完成此操作。

有什么办法可以提高性能吗?

一个好的解决方案可能是放弃NHibernate来完成此任务,然后将数据插入临时表中,然后在该临时表上进行联接。

但是,如果您想使用NHibernate,则可以通过不发出10,000个单独的查询(现在正在发生)来加快处理速度。 您可以尝试将查询分成适当大小的块:

List<object[]> ProcessChunk(
    IStatelessSession session,
    int start,
    IEnumerable<Registro> currentChunk)
{
    var disjunction = Restrictions.Disjunction();

    foreach (var item in currentChunk)
    {
        var restriction = Restrictions.Conjunction()
            .Add(Restrictions.Where<Registro>(t => t.Asunto == item.Asunto))
            /* etc, calling .Add(..) for every field you want to include */

        disjunction.Add(restriction);
    }

    return session.QueryOver<Registro>()
        .Where(disjunction)
        .SelectList(list => list
            .Select(t => t.Id)
            /* etc, the rest of the select list */
        .List<object[]>()
        .ToList();
}

然后从主循环调用该方法:

const int chunkSize = 500;   

for (int kr = 0; kr < records.Length; kr += chunkSize)
{
    var currentChunk = records.Skip(i).Take(chunkSize);

    resultList.AddRange(ProcessChunk(session, i, currentChunk));
}

您在这里所做的是发出20个(而不是10,000个)查询,如下所示:

select
    /* select list */
from
    [Registro]
where
    ([Registro].[Asunto] = 'somevalue' and ... and ... and .. ) or
    ([Registro].[Asunto] = 'someothervalue' and ... and ... and ... )
    /* x500, one for each item in the chunk */

等等。 如果每个块的大小为500,则每个查询最多返回500条记录。

这仍然不会很快。 我在本地测试中将运行时间减少了一半。

根据数据库引擎的不同,您可能会很快遇到可以传递的最大参数数量。 您可能必须使用chunkSize才能正常工作。

如果使用临时表并放弃NHibernate,则可能将其减少到几秒钟。

暂无
暂无

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

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