c# - 多线程 SQL 选择语句

标签 c# sql-server multithreading task

本人是多线程新手,也是SQL新手,菜鸟犯错请见谅。

我正在尝试异步执行许多 SQL 查询。查询都是来自同一数据库中同一表的所有选择语句。我可以同步运行它们并且一切正常,但是测试一小部分让我相信同步运行所有查询大约需要 150 小时,这太长了。因此,我试图弄清楚如何并行运行它们。

我尝试在 run a method multiple times simultaneously in c# 的答案之后对代码建模,但我的代码没有正确执行(这是错误的,虽然我不知 Prop 体是如何发生的。代码只是说发生了错误)。

这是我所拥有的(我实际正在做的事情的一个更小更简单的版本):

class Program
{
    static void Main(string[] args)
    {
        List<string> EmployeeIDs = File.ReadAllLines(/* Filepath */);
        List<Tuple<string, string>> NamesByID = new List<Tuple<string, string>>();

        //What I do not want to do (because it takes too long) ...
        using (SqlConnection conn = new SqlConnection(/* connection string */))
        {
            foreach (string id in EmployeeIDs)
            {
                using (SqlCommand cmd = new SqlCommand("SELECT FirstName FROM Employees WITH (NOLOCK) WHERE EmployeeID = " + id, conn))
                {
                    try
                    {
                        conn.Open();
                        NamesByID.Add(new Tuple<string, string> (id, cmd.ExecuteScalar().ToString()));
                    }
                    finally
                    {
                        conn.Close();
                    }
                }
            }
        }


        //What I do want to do (but it errors) ...
        var tasks = EmployeeIDs.Select(id => Task<Tuple<string, string>>.Factory.StartNew(() => RunQuery(id))).ToArray();
        Task.WaitAll(tasks);
        NamesByID = tasks.Select(task => task.Result).ToList();
    }

    private static Tuple<string, string> RunQuery(string id)
    {
        using (SqlConnection conn = new SqlConnection(/* connection string */))
        {
            using (SqlCommand cmd = new SqlCommand("SELECT FirstName FROM Employees WITH (NOLOCK) WHERE EmployeeID = " + id, conn))
            {
                try
                {
                    conn.Open();
                    return new Tuple<string, string> (id, cmd.ExecuteScalar().ToString());
                }
                finally
                {
                    conn.Close();
                }
            }
        }
    }
}

注意:我不关心这是如何实现多线程的(任务、parallel.foreach、backgroundworker 等)。这将用于运行 ~30,000 个选择查询恰好 1 次,所以我只需要它快速运行一次(我希望 ~8 小时 = 一个工作日,但我会尽我所能)一次.它不一定非常漂亮。

提前致谢!

最佳答案

这完全是错误的。您应该构建一个查询来选择您需要的所有 FirstNames。如果你需要向服务器传递一堆 id,那没问题,只需使用 table valued parameter (又名 TVP),逗号分隔的值列表确实不能很好地扩展。如果查询被正确编写并且表被索引,那应该是相当快的。 100k 行表是一个小表。

查询可能看起来像这样

SELECT DollarAmount, comp.CompanyID
FROM Transactions 
JOIN (SELECT MIN(TransactionID) as minTransactionID, CompanyID 
      FROM CompanyTransactions       
      GROUP BY CompanyID
     ) AS comp 
ON Transactions.TransactionID = comp.minTransactionID
JOIN @IDList ON id = comp.CompanyID

如果 TVP 中的 ID 不唯一,您可以使用 IN 而不是 JOIN

顺便说一句。你知道NOLOCK是什么意思吗?如果您是数据库的唯一用户并且单线程使用它或不修改任何数据,那么您是安全的。除此之外,这意味着您还可以:

  • 结果中可能缺少一些记录
  • 结果中有重复记录
  • 结果中有一些行从未被提交,也从未被接受为有效数据
  • 如果您使用 varchar(max),您可能会得到从未存储过的文本

关于c# - 多线程 SQL 选择语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46208535/

相关文章:

c# - 刷新 Windows 窗体中的 list 框

c# - 在 .Net 中阻塞一个线程

sql-server - 如何在维度表上打乱唯一键值?

c# - AutoResetEvent 与 bool 值停止线程

c# - 在 Xamarin.Forms 上的 XAML 中将 BindingContext 设置为 ViewModel

c# - Storyboard动画停不下来,我只能开始

sql-server - 如何将整数转换为对齐左侧文本的文本?

sql-server - 使用 SQL Server 字符串函数提取值

c# - 获得锁后枚举器线程安全吗?

ruby - 在 Ruby 中实现生产者消费者模式