【问题标题】:What is the correct way to deal with procedures that take a "long time" to complete?处理需要“长时间”完成的程序的正确方法是什么?
【发布时间】:2008-10-31 15:34:27
【问题描述】:

我在 Visual Studio 2005 Pro 中创建了一个 Winforms 应用程序,它使用 SqlConnection / SqlCommand / SqlDataAdapter 类连接到 SQL Server 2005 数据库以提取数据。我已经在我的数据库中存储了过程来将数据返回给我。

处理需要“很长时间”才能完成的查询的最佳方法是什么? (即足够长,用户开始认为有问题)。目前,我的应用程序会锁定,直到查询完成或查询超时。显然这是不可接受的。

我至少想要一个带有“停止”按钮的进度表。进度条甚至不需要做任何有用的事情,提示耐心地坐着等待就足够了。

最好是一个警告,上面写着“这将返回 140,000 行数据。你想继续吗?”

我知道这可能需要线程,但是如何?

【问题讨论】:

    标签: c# database sql-server-2005 multithreading visual-studio-2005


    【解决方案1】:

    确保优化查询是第一步,但之后,您必须使用线程,而 .NET 为这些情况提供了 BackgroundWorker component

    这是complete example

    【讨论】:

      【解决方案2】:

      简单的 C# 2.0 示例:

          private void Form_Load(object sender, EventArgs e)
          {
              BackgroundWorker bw = new BackgroundWorker();
              bw.DoWork += new DoWorkEventHandler(bw_DoWork);
              bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
              //change UI to reflect we're doing this
              bw.RunWorkerAsync();
          }
      
          void bw_DoWork(object sender, DoWorkEventArgs e)
          {
              //SQL Work
          }
      
          void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
          {
              //Let the user know we're done
          }
      

      【讨论】:

        【解决方案3】:

        好的,首先,我建议您尝试加快查询速度。首先要检查的是确保您有适当的索引。网上有大量关于正确使用索引的文章。

        如果在这一切之后,您的查询仍然太慢,您可能不得不切换到使用数据库游标。

        使用光标,您一次读取一个结果,然后拉出它们。这将使您有机会显示进度条。

        如果您坚持当前的查询模型并简单地使用线程来绘制进度条,那么您的进度条将与正在完成的工作无关并且看起来不正确。

        【讨论】:

          【解决方案4】:

          我在创建长文件时使用 RunWorker 和 ProgressBar。

          我使用的一个技巧是在设置 ProgressBar 时找到要使用的文件长度的代理。例如,ProgressBar 可能基于函数上次运行时文件中的行数(可能保存在一个长文件中)。 ProgressBar 或类似的,不必精确。

          【讨论】:

            【解决方案5】:

            要实现您的警告,您可以首先发出 COUNT() 查询,该查询不仅会返回用户将要获取的行数,而且可能会开始缓存数据。

            【讨论】:

            • 另一方面,COUNT 可能需要很长时间并且需要自己的进度条!
            • 确实如此......但这是一个想法:)
            【解决方案6】:

            您可能希望创建另一个表来记录查询的执行时间。这样你就可以说“上次这个过程花了 X 时间”。这将为他们提供对需要多长时间的粗略估计。否则你将不得不运行一个查询来获得一个可能需要很长时间的 COUNT。

            【讨论】:

              【解决方案7】:

              您会想要利用线程。当用户发出获取数据的信号时,您可以生成一个新线程来获取数据,同时在主窗体上显示一个 throbber。当线程返回时,您可以做出反应并显示结果。

              【讨论】:

                【解决方案8】:

                对于您的进度条,请查看 Marquee 样式。如果由于某种原因无法获得实际的进度报告(也就是说,如果使用 CURSOR 作为 dicroce 建议的结果是站不住脚/太慢/无论如何),您可以使用 Marquee 进度条来显示您的 UI 仍在响应,并且您没有忘记用户。

                请记住 Jakob Nielsen 的规则:如果您花费超过 250 毫秒 (?) 来返回给用户,他们会担心出现问题。通常,您的按钮应该运行任何必要的验证(快点!),然后显示一些告诉用户“我正在工作”并将控制权返回给 UI 循环的内容。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2014-04-14
                  • 2013-02-06
                  • 1970-01-01
                  相关资源
                  最近更新 更多