如何限制网络请求期间的数据库查询时间?

发布于 2024-10-25 11:46:34 字数 214 浏览 1 评论 0原文

我们有一个在 postgresql 9.0 上运行的非常典型的 django 应用程序。我们最近发现一些数据库查询由于管理界面中的搜索效率低下而运行了超过 4 小时。虽然我们计划修复这些查询,但作为一种保护措施,我们希望人为地将数据库查询时间限制为 15 秒——但仅限于 Web 请求的上下文中;批处理作业和 celery 任务不应受此约束的限制。

我们怎样才能做到这一点?或者这是一个糟糕的主意?

We've got a pretty typical django app running on postgresql 9.0. We've recently discovered some db queries that have run for over 4 hours, due to inefficient searches in the admin interface. While we plan to fix these queries, as a safeguard we'd like to artificially constrain database query time to 15 seconds--but only in the context of a web request; batch jobs and celery tasks should not be bounded by this constraint.

How can we do that? Or is it a terrible idea?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

隔纱相望 2024-11-01 11:46:34

执行此操作的最佳方法是设置仅用于运行 Web 请求的角色/用户,然后在该角色上设置 statements_timeout。

ALTER ROLE role_name SET statement_timeout = 15000

所有其他角色将使用statement_timeout 的全局设置(在库存安装中禁用)。

The best way to do this would be to set up a role/user that is only used to run the web requests, then set the statement_timeout on that role.

ALTER ROLE role_name SET statement_timeout = 15000

All other roles will use the global setting of statement_timeout (which is disabled in a stock install).

赠佳期 2024-11-01 11:46:34

您需要手动处理这个问题。即检查 15 秒规则并终止违反该规则的查询。

查询 pg_stat_activity 并找到违规者并调用 pg_terminate_backend(procpid) 来杀死违规者。

循环中是这样的:

SELECT pg_terminate_backend(pg_stat_activity.procpid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB'
  AND usename = 'WEBUSERNAME'
  AND (now()-query_start) > '00:00:15';

You will need to handle this manually. That is checking for the 15 second rule and killing the queries that violate it.

Query pg_stat_activity and find the violators and issue calls to pg_terminate_backend(procpid) to kill the offenders.

Something like this in a loop:

SELECT pg_terminate_backend(pg_stat_activity.procpid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB'
  AND usename = 'WEBUSERNAME'
  AND (now()-query_start) > '00:00:15';
策马西风 2024-11-01 11:46:34

就计时而言,您可以通过一个类传递所有查询,该类在实例化时会生成两个线程:一个用于查询,另一个用于计时器。如果计时器达到 15 秒,则终止带有查询的线程。

至于确定查询是否是从 Web 请求实例化的,我对 Django 的了解还不够,无法帮助您。简单地说,在处理数据库调用的类中,构造函数的可选参数可以是类似于 context 的内容,如果发生以下情况,则可以是 http Web 请求和 "" 用于其他任何内容。

As far as the timing goes, you could pass all of your queries through a class which, on instantiation, spawns two threads: one for the query, and one for a timer. If the timer reaches 15 seconds, then kill the thread with the query.

As far as figuring out if the query is instantiated from a web request, I don't know enough about Django to be able to help you. Simplistically, I would say, in your class that handles your database calls, an optional parameter to the constructor could be something like context, which could be http in the event of a web request and "" for anything else.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文