C# 使用EF6从数据库中异步选择大量数据

C# 使用EF6从数据库中异步选择大量数据,c#,.net,entity-framework,asynchronous,async-await,C#,.net,Entity Framework,Asynchronous,Async Await,我试图做的是从一个大约有400万行的表中获取行,以便根据ElasticSearch对其进行索引 底层索引器将使用IndexManySync并批量处理给定给它的枚举 比如: public void IndexMany(IEnumerable<IIndexModel> indexModels) { var client = new ElasticClient(settings); var batches = indexModels.Batch(1000); var

我试图做的是从一个大约有400万行的表中获取行,以便根据ElasticSearch对其进行索引

底层索引器将使用IndexManySync并批量处理给定给它的枚举

比如:

public void IndexMany(IEnumerable<IIndexModel> indexModels) {
    var client = new ElasticClient(settings);
    var batches = indexModels.Batch(1000);
    var tasks = new List<Task>();
    Parallels.ForEach(partitions, partition =>
    {
        var task = client.IndexManyAsync(partition);
        tasks.Add(task);
    }

    Task.WaitAll(tasks.ToArray());
}
public class FooModel<T> : IIndexModel
{
    public FooModel(T entity) 
    {
        Name = entity.Name;
    }

    public string Name { get; set; }
}
public void IndexMany(IEnumerable indexModels){
var客户端=新的ElasticClient(设置);
var批次=indexModels.Batch(1000);
var tasks=新列表();
Parallels.ForEach(分区,分区=>
{
var task=client.indexmanyanc(分区);
任务。添加(任务);
}
Task.WaitAll(tasks.ToArray());
}
因此,考虑到这一点,我想用IndexModels创建一个可枚举的

IndexModels将获取一个实体并通过给定实体初始化各种属性。类似于:

public void IndexMany(IEnumerable<IIndexModel> indexModels) {
    var client = new ElasticClient(settings);
    var batches = indexModels.Batch(1000);
    var tasks = new List<Task>();
    Parallels.ForEach(partitions, partition =>
    {
        var task = client.IndexManyAsync(partition);
        tasks.Add(task);
    }

    Task.WaitAll(tasks.ToArray());
}
public class FooModel<T> : IIndexModel
{
    public FooModel(T entity) 
    {
        Name = entity.Name;
    }

    public string Name { get; set; }
}
公共类FooModel:IIndexModel
{
公共模型(T实体)
{
Name=实体名称;
}
公共字符串名称{get;set;}
}
我有一个表,其中包含~4mil行,这显然需要一些时间来查询。所以我想做的是异步执行此操作

我尝试过各种方法。第一种方法是对查询进行批处理,并对其执行并行foreach。这给ObjectContext带来了各种并发问题

public void IndexAllModels() {
    using (var db = new Db()) {
        var batchedEntities = db.BigTable.Select(p => p).Batch(1000);

        Parallels.ForEach(batchedEntities, currentBatch =>
        {
            var indexModels = new List<IIndexModel>();
            foreach (var entity in currentBatch) 
            {
                var indexModel = new FooModel<BigTable>(entity);
                indexModels.Add(indexModel);
            }

            IndexMany(indexModels);
        }
    }
}
public void IndexAllModels(){
使用(var db=new db()){
var batchedenties=db.BigTable.Select(p=>p.Batch(1000);
Parallels.ForEach(batchedEntities,currentBatch=>
{
var indexModels=新列表();
foreach(currentBatch中的var实体)
{
var indexModel=新模型(实体);
添加(indexModel);
}
IndexMany(indexModels);
}
}
}

我想知道的是,通过使用新的EF6异步操作,是否有办法做到这一点?

使用Natural
async
API的优点是,您不需要使用线程来使用它们。因为一直到WinAPI级别

您可以创建一个采用
IEnumerable
的方法,并使用ElasticSearchs的异步API,如下所示:

public async Task IndexManyAsync(IEnumerable<IIndexModel> indexModels) 
{
    var client = new ElasticClient(settings);

    var taskBatches = indexModels.Batch(1000)
                                 .Select(partition =>
                                         client.IndexManyAsync(partition));

    await Task.WhenAll(taskBatches);
}
公共异步任务IndexManyAsync(IEnumerable indexModels)
{
var客户端=新的ElasticClient(设置);
var taskBatches=indexModels.Batch(1000)
.选择(分区=>
indexmanyanc(分区));
等待任务。WhenAll(任务批次);
}

假设
indexmanysync
为每个请求使用单独的
DbContext
,这应该会起作用。

indexModels的大小可能会有所不同。一些indexModels设置了大约20个属性,而一些仅设置了大约5个。多达400万个索引模型。当支持ElasticSearch时,为什么要使用ORM对数据库进行爬网已经通过JDBC连接的ts?使用ORM没有任何好处(没有涉及任何对象)但是,通过一个只沿列传递数据的中介,确实会增加大量开销!这解释了一些问题。但是,这并不能回答如何从数据库异步检索大块数据的问题。我的问题可能不是很清楚。但选择4百万行也可能是内存问题。@Ekenstein哦,我以为您已经在使用
Batch
来处理每1000个请求。是的。我使用morelinq来批处理查询。但是,当尝试使用parallel foreach获取每个批时,它会变得很麻烦,因为objectcontext似乎不是线程安全的。此外,我还希望为每个并行实体实例化一个索引模型还有。@Ekenstein为什么要使用ORM来抓取数据库?你永远不会达到ElasticSearch直接抓取数据库的速度,更不用说ORM不适合批处理/设置操作了。@Ekenstein你可以通过指定一个视图而不是表本身来完成。即使你必须使用中间处理步骤(例如,对于一些无法在SQL中进行压缩的复杂计算)使用SqlReader作为firehose游标并立即或成批将每个处理的行发送给ElasticSearch会更快、更简单、更便宜。只有当您希望多个这样的通道同时从数据库加载数据时,并发才会有所帮助—假设ElasticSearch可以处理该加载