![](/img/trans.png)
[英]ASP.Net/SQL: After cancelling query the memory isn't decreasing (DataBoundControl.PerformSelect)
[英]Cancelling SQL Query in background in .NET
我正在设计一个小型桌面应用程序,该应用程序可以从SQL Server提取数据。 我使用BackgroundWorker
使查询在后台执行。 提取数据的代码通常可以归结为:
public static DataTable GetData(string sqlQuery)
{
DataTable t = new DataTable();
using (SqlConnection c = new SqlConnection(GetConnectionString()))
{
c.Open();
using (SqlCommand cmd = new SqlCommand(sqlQuery))
{
cmd.Connection = c;
using (SqlDataReader r = cmd.ExecuteReader())
{
t.Load(r);
}
}
}
return t;
}
由于查询可能需要10到15分钟,因此我想实施取消请求并将其从GUI层传递到DAL。 BackroundWorker
取消过程不会让我取消SqlCommand.ExecuteReader()
因为它仅在从服务器获取数据或数据提供者引发异常时才停止。 我试图使用Task
和SqlCommand.ExecuteReaderAsync(CancellationToken)
async/await
,但是我很困惑在多层应用程序(GUI-> BLL-> DAL)中使用它的位置。
您是否尝试过使用SqlCommand.Cancel()方法?
方法:将GetData
方法封装在线程/工作器中,然后在您取消/停止该线程时,对正在执行的SqlCommand
调用Cancel()
方法。
这是有关如何在线程上使用它的示例
using System;
using System.Data;
using System.Data.SqlClient;
using System.Threading;
class Program
{
private static SqlCommand m_rCommand;
public static SqlCommand Command
{
get { return m_rCommand; }
set { m_rCommand = value; }
}
public static void Thread_Cancel()
{
Command.Cancel();
}
static void Main()
{
string connectionString = GetConnectionString();
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
Command = connection.CreateCommand();
Command.CommandText = "DROP TABLE TestCancel";
try
{
Command.ExecuteNonQuery();
}
catch { }
Command.CommandText = "CREATE TABLE TestCancel(co1 int, co2 char(10))";
Command.ExecuteNonQuery();
Command.CommandText = "INSERT INTO TestCancel VALUES (1, '1')";
Command.ExecuteNonQuery();
Command.CommandText = "SELECT * FROM TestCancel";
SqlDataReader reader = Command.ExecuteReader();
Thread rThread2 = new Thread(new ThreadStart(Thread_Cancel));
rThread2.Start();
rThread2.Join();
reader.Read();
System.Console.WriteLine(reader.FieldCount);
reader.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
static private string GetConnectionString()
{
// To avoid storing the connection string in your code,
// you can retrieve it from a configuration file.
return "Data Source=(local);Initial Catalog=AdventureWorks;"
+ "Integrated Security=SSPI";
}
}
您只能在不同的代码行之间进行取消检查和进度报告。 通常,两者都要求您将代码分解到最低的循环级别,因此您可以在循环触发之间/之中进行这两项操作。 当我写到BGW的第一步时,我的优势是无论如何我都需要执行循环,所以这不需要额外的工作。 您遇到的最坏情况之一是-只能复制或按原样使用的预先存在的代码。
理想情况:
此操作应该花的时间不多。 5至10分钟表示您的设计存在某些问题。
如果大部分时间是在传输数据,那么您很可能会撤回大量数据的方法。 检索所有内容以在GUI中进行过滤是一个非常常见的错误。 尽可能在查询中进行过滤。 Usign分布式数据库也可能有助于提高传输性能。
如果大部分时间都作为查询操作的一部分(复杂条件)进行处理,那么您一般方法中的某些内容可能必须更改。 在DBMS端有一些内存可以通过多种方式来权衡复杂的计算。 视图afaik可以缓存操作结果,同时仍保持事务一致性。
但这实际上取决于您的后端DB / DBMS和用例。 很多使用SQL作为查询语言。 因此,它不允许我们预测您拥有的选择。
第二好的情况:
如果您不能削减它的第二件事,那就是您是否将实际的数据库访问代码缩减到最低的循环,并对其进行进度报告/取消检查。 这样,您实际上可以使用BGW中固有的现有取消令牌系统。
其他一切
使用任何其他取消方法实际上是一个后备。 我写了很多关于它为什么不好的文章,但是我觉得如果专注于核心问题,这可能会更好-在DB和/或Query的设计中可能出了点问题。 因为这些完全可以消除问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.