2

在我的项目中,我正在运行一个返回大量数据的大规模查询。由于此查询的大小,运行时间有时会超过 1 分钟。忽略这可能产生的其他问题,有没有办法取消当前正在运行的查询?

例如,用户启动查询并被重定向到标准的“正在加载结果...”页面。如果他们随后决定不再需要结果,他们可以单击“取消”按钮,该按钮将以某种方式终止正在运行的查询。

这可能吗?怎么做?

谢谢!

4

3 回答 3

3

尝试使用pg_cancel_backend

从文档:

取消后端的当前查询。您可以针对与调用该函数的用户具有完全相同角色的另一个后端执行此操作。在所有其他情况下,您必须是超级用户。

于 2013-08-05T21:31:45.927 回答
1

我知道的唯一方法是重新启动数据库,尽管有时您可以发送取消信号,具体取决于数据库设置。你可以看看 rack-timeout gem 吗?

真正的问题是您的查询不应该花那么长时间,我强烈建议不要以这种方式解决问题。更好的方法是检查查询并尝试优化它。很少,如果有的话,应该合法地花费超过 1 分钟才能完成的查询。将数据转储到您的本地计算机上并在查询上运行 EXPLAIN 以查找瓶颈。通过添加正确的索引,我已经将 142 秒的大型查询降低到 <3 秒,所以如果你不能获得相同的效果,我会感到惊讶。

于 2013-08-05T20:55:59.933 回答
1

我最近做了这样的事情(在我们的应用程序中添加了一个“取消”按钮)。下面是我一起破解的 plpgsql 函数,它基本上是函数的包装器pg_cancel_backend()

注意事项:

1)。您的应用程序必须创建一个唯一的 id(或 UUID)并将其作为“p_uid”参数传递给函数。

2)。我对应用程序用户进行了硬编码(不会改变)。

3)。Postgresql 9.0+(这是为 9.2 创建的,在任何早期版本中都未经测试)

4)。可以在该功能中加强安全性。

CREATE OR REPLACE FUNCTION public.cancel_user_query(p_uid TEXT, OUT retval BOOLEAN) RETURNS boolean
AS $function$
DECLARE
BEGIN
    /*  The pg_sleep() call at the start is because if a user issues a query
        then promptly tries to kill it, it will likely not have shown up in the
        pg_stat_activity view yet (there is a delay before it appears).
        XXX: The GUC setting "track_activities" *MUST* be enabled for this to work.
    */

    retval := FALSE;
    IF ( current_setting('track_activities')::BOOLEAN IS NOT TRUE ) THEN
        RAISE WARNING '[PUBLIC.CANCEL_USER_QUERY] - "track_activities" *MUST* be enabled for this to work';
        RETURN;
    END IF;

    /* In a system under regular high load, this might need to be bumped higher than 2 seconds */
    PERFORM pg_sleep(2); 

    WITH q AS ( SELECT pid FROM pg_stat_activity WHERE LOWER(usename) = 'YOUR_APP_USER' AND application_name = p_uid AND state <> 'idle' )
    SELECT pg_cancel_backend(pid) AS retval
    INTO retval
    FROM q;

    if ( retval IS NOT TRUE ) then
        retval := FALSE;
    end if;

    RETURN;

EXCEPTION
    WHEN others THEN
        RAISE WARNING '[PUBLIC.CANCEL_USER_QUERY] - ERROR: %',sqlerrm;
        retval := FALSE;
        RETURN;
END;
$function$ LANGUAGE plpgsql SECURITY DEFINER;

单击“取消查询”按钮后,应用程序将执行该功能并检查返回的状态。例如。SELECT retval FROM public.cancel_user_query('asifdaqiwaviafasdf') retval

于 2013-08-05T22:53:24.107 回答