【问题标题】:ExecuteSqlCommand parallel executionExecuteSqlCommand 并行执行
【发布时间】:2014-02-06 09:52:45
【问题描述】:

SQL Server 11.0.3、C# .NET 4.5、WCF、EF v4.0.30319

我有下表存储查询:

OBJECT_TYPE     OBJECT_NAME         OBJECT_TYPE_NAME    OBJECT_QUERY
1               HUB_PERSON          HUB                 MERGE INTO ...
1               HUB_GPS             HUB                 MERGE INTO ...
2               LNK_PERSON_GPS      LNK                 MERGE INTO ...
2               SAT_CURR_PERSON     SAT                 MERGE INTO ...
2               SAT_GPS             SAT                 MERGE INTO ...
2               SAT_HIST_PERSON     SAT                 MERGE INTO ...

我必须按照OBJECT_TYPE 列指定的顺序从我的服务中执行查询。具有相同OBJECT_TYPE 的查询可以按任何顺序执行,这就是为什么我想尽可能并行执行这些查询。

这是我目前正在使用的函数,没有并行性:

public int ExecuteLoadSources()
        {
            int nb = 0;
            using (POCDVEntities POCDb = new POCDVEntities())
            {
                using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required))
                {
                    IEnumerable<string> res = (
                        from a in POCDb.LOADING_SOURCE_QUERY
                        orderby a.OBJECT_TYPE
                        select a.OBJECT_SQLSRV_QUERY
                    );
                    foreach (string req in res)
                    {
                        POCDb.Database.ExecuteSqlCommand(req);
                    }
                    nb = POCDb.SaveChanges();
                    transaction.Complete();
                }
            }
            return nb;
        }

我试过这样Parallel.ForEach

public int ExecuteLoadSources()
        {
            int nb = 0;
            using (POCDVEntities POCDb = new POCDVEntities())
            {
                using (TransactionScope transaction = new TransactionScope(TransactionScopeOption.Required))
                {
                    IEnumerable<string> res = (
                        from a in POCDb.LOADING_SOURCE_QUERY
                        select a.OBJECT_SQLSRV_QUERY
                    );
                    int maxValue = (from a in POCDb.LOADING_SOURCE_QUERY select a.OBJECT_TYPE).Max();
                    for (int i = 1; i <= maxValue; i++)
                    {
                        IEnumerable<string> res2 = (
                            from a in POCDb.LOADING_SOURCE_QUERY
                            where a.OBJECT_TYPE == i
                            select a.OBJECT_SQLSRV_QUERY
                        ).ToList();
                        Parallel.ForEach(res2, req2 =>
                        {
                            POCDb.Database.ExecuteSqlCommand(req2);
                        });
                    }
                    nb = POCDb.SaveChanges();
                    transaction.Complete();
                }
            }
            return nb;
        }

第一次运行该函数时,我得到The underlying provider failed on Open.,然后我再次尝试获取Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.

我做得对吗? 有什么建议吗?

【问题讨论】:

  • 好吧,我不认为SqlConnection 可以同时从多个线程中使用,即使使用 MARS。而Parallel.ForEach 会将ExecuteSqlCommand 放到另一个线程上,这可能会使TransactionScope 无用。
  • 好的,所以我可以假设这是不可能的?

标签: c# sql-server linq entity-framework parallel.foreach


【解决方案1】:

我可以对此给出一个抽象的答案,它可能不会直接回答您的问题(而且我没有代表发表评论),但对于此类问题,它仍然是有价值的信息。

您尝试执行的操作存在一些问题。

首先是数据库上下文(以及扩展的 sql 连接)和线程并发。您绝对不能跨线程共享连接,您必须在每个线程上创建一个新连接,因为它是并行生成的。由于连接池,这实际上不是一个错误处理,所以无论如何你的性能影响是最小的。因此,在您的情况下,您需要在并发块内创建上下文实例。

第二个是在事务内部对数据库执行并行查询通常不是一个好策略。这样做的原因是,当您在同一个数据库上同时运行多个查询时,您需要注意您的隔离模式。根据连接和全局设置,您可能会敲打您的日志/日志并调用 DTC。如果您的整个查询集必须作为一个整体在事务上是安全的,那么并行运行查询根本不会使您受益,而应该按顺序运行每个查询。如果只有每个单独的查询必须是事务安全的,那么您应该在并发块内创建事务上下文。

最后只是建议使用Task 而不是Parallel。拥有可以并行运行的任务嵌套结构比在循环中执行并行并发块更具组织意义。在这种情况下,您将拥有一个主任务(您可以在 Wait() 上打开),其中每个 OBJECT_TYPE 都有子任务。您可以通过在查询数据集上迭代 GroupBy 查询来生成 Task 结构。就像前面所说的,这只是一个建议,并不是真正需要完成查询的并行执行。

还有一点需要考虑(类似于Task 策略),就是使用异步方法来执行每个查询,然后使用一个简单的函数来调用每个异步方法并在最后等待。只是一个想法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多