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

3

我想做的是从一张大约有四百万行的表中获取数据,将其与ElasticSearch建立索引。

底层的索引器会使用IndexManyAsync并将给定的可枚举对象分批处理。

类似于:

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());
}

考虑到这一点,我想创建一个具有IndexModels的可枚举对象。

IndexModels将通过给定的实体初始化各种属性。类似于:

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

    public string Name { get; set; }
}

我有一个包含大约4百万行记录的表格,查询肯定需要一些时间。因此,我希望能够异步地进行查询。
我已经尝试了多种方法。首先是将查询分批,并在其上执行并行循环,但这会引发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);
        }
    }
}

我想知道是否有使用新的EF6异步操作来完成这个任务的方法?

indexModels 的大小是多少? - i3arnon
有些索引模型设置大约20个属性,而有些只有5个左右。 - Ekenstein
多达约400万个索引模型。 - Ekenstein
为什么要使用ORM来爬取数据库,当ElasticSearch已经通过JDBC连接支持了这一点呢?你不会从使用ORM中获得任何好处(因为没有对象参与),但是你确实会增加显着的开销,因为需要通过一个中介来传递数据。 - Panagiotis Kanavos
1个回答

2
使用自然的async API的优点是无需使用线程即可使用它们。因为一直到WinAPI级别,没有线程
您可以创建一个方法,该方法需要一个IEnumerable<IndexModel>并使用ElasticSearch的异步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);
}

假设每个请求使用单独的DbContext,那么这应该可以工作。

谢谢!这解释了一些问题。然而,这并没有回答如何异步从数据库检索大块数据的问题。 我可能在我的问题表述上不够清晰。 但选择4百万行也可能是一个内存问题。 - Ekenstein
@Ekenstein 哦,我以为你已经在使用“批处理”来处理每1000个请求了。 - Yuval Itzchakov
@Ekenstein 为什么要使用ORM来爬取数据库?你永远无法像直接使用ElasticSearch爬取那样获得相同的速度,更不用说ORM对于批量/集合操作是不适合的。 - Panagiotis Kanavos
一些数据库中的信息不应该被索引。这就是为什么。 - Ekenstein
1
@Ekenstein,您可以通过指定视图而不是表本身来实现。即使您必须使用中间处理步骤(例如某些无法用SQL表达的复杂计算),使用SqlReader作为firehose游标并立即或分批将每个处理过的行发送到ElasticSearch会更快、更容易和更便宜。并发仅在您想要从数据库并发加载多个这样的通道时才有帮助-假设ElasticSearch可以处理该负载。 - Panagiotis Kanavos
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接