Parallel.Foreach SQL querying sometimes results in Connection

后端 未结 3 861
暖寄归人
暖寄归人 2021-01-01 04:37

I need to speed up performing 12 queries in my application. I switched from a regular foreach to Parallel.ForEach. But sometimes I get an error saying \"ExecuteReader requ

相关标签:
3条回答
  • 2021-01-01 04:49

    I would refactor out your business logic (connecting to the database).

    public class SqlOperation
    {
        public SqlOperation()
        {
            Queries = new List<string>();
        }
    
        public string TableName { get; set; }
        public string ConnectionString { get; set; }
        public List<string> Queries { get; set; }
    }
    
    public static List<DataTable> GetAllData(IEnumerable<SqlOperation> sql)
    {
        var taskArray =
            sql.SelectMany(s =>
                s.Queries
                 .Select(query =>
                    Task.Run(() => //Task.Factory.StartNew for .NET 4.0
                        ExecuteQuery(s.ConnectionString, s.TableName, query))))
                .ToArray();
    
        try
        {
            Task.WaitAll(taskArray);
        }
        catch(AggregateException e)
        {
            MessageBox.Show(e.ToString(), "GetAllData error");
        }
    
        return taskArray.Where(t => !t.IsFaulted).Select(t => t.Result).ToList();
    }
    
    public static DataTable ExecuteQuery(string connectionString, string tableName, string query)
    {
        DataTable dataTable = null;
    
        using (var connection = new SqlConnection(connectionString))
        {
            dataTable = new DataTable();
            dataTable.TableName = tableName;
            using(var command = new SqlCommand(query, connection))
            {
                connection.Open();
    
                using(var adapter = new SqlDataAdapter())
                {
                    adapter.SelectCommand = command;
                    adapter.Fill(dataTable);
                }
            }
        }
    
         return dataTable;
    }
    
    0 讨论(0)
  • 2021-01-01 04:53

    Ado.Net has a pretty clever connection pooling, so in general you should just open connections and close connections per command and let the pool handle whether they are really being opened or closed.

    So one connection per command:

      Parallel.ForEach(sql, s=>
                //foreach (Sql s in sql)
                {
                    foreach (string q in s.queries)
                    {
                        using (connection = new SqlConnection(s.connection))
                        {
                            connection.Open();
                            DataTable dt = new DataTable();
                            dt.TableName = s.name;
                            command = new SqlCommand(q, connection);
                            SqlDataAdapter adapter = new SqlDataAdapter();
                            adapter.SelectCommand = command;
                            adapter.Fill(dt);
                            //adapter.Dispose();
    
                            lock(data){
                                data.Add(dt);
                            }
                        }
                    }
                }
    
    0 讨论(0)
  • 2021-01-01 05:07

    You can also use MultipleActiveResultSets=true; in connection string to support multiple readers

    0 讨论(0)
提交回复
热议问题