如何取消长时间运行的数据库操作?

问题描述 投票:26回答:10

目前正在与Oracle合作,但也需要一个MS SQL解决方案。

我有一个GUI,允许用户生成将在数据库上执行的SQL。这可能需要很长时间,具体取决于它们生成的搜索。我希望GUI / App在此搜索期间能够响应,我希望用户能够取消搜索。

我正在使用后台工作线程。

我的问题是,当用户取消搜索时,我无法中断对数据库的调用。它等待它完成然后,它可以轮询'CancelationPending'属性。这不仅浪费了数据库上的资源,而且还为我的代码带来了问题。

如果用户在非常长的查询中点击“搜索”,则再次点击“取消”,然后再次“搜索” - 第一次搜索仍然在数据库上进行搜索。后台工作人员再次点击搜索时仍然很忙。我遇到这个问题的唯一方法就是建立一个新的后台工作者。

这似乎是一种非常丑陋的做事方式。数据库继续工作我正在创建后台工作者的新实例....当我真的想要停止数据库调用并重新使用同一个worker时。

我怎样才能做到这一点?

.net database oracle asynchronous backgroundworker
10个回答
-1
投票

我不认为这是可能的。以下是有关此主题的Oracle网站讨论的链接:http://forums.oracle.com/forums/thread.jspa?threadID=400492&start=15&tstart=0


0
投票

KILL SESSION是我取消长时间运行查询的唯一工作方式。我使用提供的托管oracle和OracleCommand.Cancel()有效,但通常它不起作用。根据我的测试,OracleCommand.CommandTimeout也不受尊重。前一段时间,当我使用非托管的oracle时,我设法取消命令,但不再使用托管的命令。杀死会话的任何方式都是唯一的选择。查询未在UI线程上运行,而是在单独的线程上运行。取消命令从UI线程发送。它有点复杂,因为应用程序使用使用WCF的middletier,但在一天结束时我正在杀死会话。在运行查询时,我必须找到并保存会话以便在必要时终止它。有很多方法可以找到sid和serial#来杀死oracle会话,我想浪费你的时间来解释你已经知道的东西。


11
投票

如果您正在使用ADO.NET和SQL数据提供程序,请查看SqlCommand.Cancel方法。这就是你想要的。但是,它会尝试取消,取消可能需要一些时间。基本上,由SQL Server决定何时授予您的取消请求。取消查询时,您应该获得一个SqlException,指示操作已被用户取消。显然,您不希望将此异常视为异常并特别处理它,例如,如果SqlException是由于用户取消操作而导致的,只需将其吞下即可。


8
投票

我还注意到command.Cancel()并没有真正中止命令。对我来说有用的是当用户中止时关闭连接(如果你使用了回滚事务)。这将在命令执行时在后台线程中引发异常,因此您必须捕获它并检查那里的CancellationPending属性,而不是在这种情况下重新抛出异常...

// When aborting
worker.CancelAsync();
command.Connection.Close();

// In your DoWork event handler
...
catch (Exception)
{
    if (worker.CancellationPending)
    {
        e.Cancel = true;
        return;
    }
    else
    {
        throw;
    }
}

// And in your RunWorkerCompleted event handler
if (e.Error == null && !e.Cancelled)
{
    ...
}

5
投票

我很确定它是可能的 - 我们使用TOAD for Oracle,它可以让你取消长时间运行的查询,as described here。我不确定他们是怎么做的。


3
投票

您可以让后台工作程序在不同的线程上触发实际的数据库调用,然后定期检查数据库调用是否已完成,或者是否已按下取消,此时您可以终止数据库线程。这实际上不会帮助数据库加载任何(因为您的查询已经发送并且仍在处理)但它确实会释放与之相关的本地资源。


3
投票

我认为最好的解决方案似乎是通过监控表杀死会话。

使用Oracle,您可以像Burnsys一样使用它

在Firebird 2.5中它会看起来像same

我希望SQL中存在类似的东西


2
投票

如果你正在使用SQLCommand,你可以尝试调用它的Cancel方法。


2
投票

如何打开与数据库的新连接,以sysdba身份登录并发送“ALTER SYSTEM KILL SESSION'sid,serial#'IMMEDIATE”命令,指定要终止的进程的SID。

要获取sessionID:从v $ mystat中选择sid,其中rownum = 1

要获得Serial#:从v $ session选择sid,serial#,其中sid =:SID

http://www.oracle-base.com/articles/misc/KillingOracleSessions.php

编辑:WW想法不登录sysdba这里:http://forums.oracle.com/forums/thread.jspa?threadID=620578


1
投票

我已尝试使用ADO 2.8和SQLOLEDB或SQL Server本机客户端取消和关闭。使用“取消”时,记录集将停止提取数据,但在后台,服务器的读取将继续并从应用程序中消耗内存。在32位应用程序中,几分钟后您可能会收到“内存不足”消息。当我关闭记录集(或连接,有或没有取消之前),ADO 2.8等待,直到获取所有记录。

我不知道ADO.NET是否做得更好,但我认为在取消/关闭后监控内存和网络访问是个好主意,以确保ADO真正停止读取数据。

© www.soinside.com 2019 - 2024. All rights reserved.