C# 使用EF6从数据库中异步选择大量数据
我试图做的是从一个大约有400万行的表中获取行,以便根据ElasticSearch对其进行索引 底层索引器将使用IndexManySync并批量处理给定给它的枚举 比如: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
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可以处理该加载