如何为查询执行设置语句超时

26 投票
1 回答
20347 浏览
提问于 2025-04-16 20:22

在我的网页应用中,有些Postgres SQL查询执行起来很慢。

我想为其中一部分查询设置超时时间。

有些查询必须在超时后被取消,而其他的查询则要不受限制地执行。

在Postgres中有一个叫做statement_timeout的功能。

我该如何将SqlAlchemy查询与statement_timeout功能结合起来呢?

像这样:

SET statement_timeout TO 1000; -- timeout for one second
<sqlalchemy generated query>;
RESET statement_timeout; -- reset

对我来说,设置查询超时的完美方法是:

users = session.query(User).timeout(0.5).all()

SqlAlchemy需要:1)设置statement_timeout 2)执行查询并返回结果 3)重置当前会话的statement_timeout

有没有其他方法可以为查询执行设置超时呢?

更新 1. 我的解决方案

我的解决方案是一个自定义连接代理(在psycopg2==2.4和SQLAlchemy==0.6.6中测试过):

from sqlalchemy.interfaces import ConnectionProxy

class TimeOutProxy(ConnectionProxy):
    def cursor_execute(self, execute, cursor, statement, parameters, context, executemany):

        timeout = context.execution_options.get('timeout', None)

        if timeout:
            c = cursor._parent.cursor()
            c.execute('SET statement_timeout TO %d;' % int(timeout * 1000))
            c.close()

        return execute(cursor, statement, parameters, context)


engine = create_engine(URL, proxy=TimeOutProxy(), pool_size=1, max_overflow=0)

这个解决方案不需要重置statement_timeout,因为每个SqlAlchemy查询都是在独立的事务中执行的,而statement_timeout是在当前事务内定义的。

使用示例(超时参数以秒为单位):

Session.query(Author).execution_options(timeout=0.001).all()

Session.bind.execute(text('select * from author;') \
      .execution_options(timeout=0.001)) \
      .fetchall()

1 个回答

3

你应该看看 SQLAlchemy 0.6 版本提供的扩展:

http://www.sqlalchemy.org/docs/06/orm/interfaces.html

这里有一些钩子,你可以在这些地方插入你的代码来处理特定的操作。

SQLAlchemy 0.7 及以上版本现在有了一个事件系统……可能会有类似的功能。可以查看一下:

http://www.sqlalchemy.org/docs/core/events.html

撰写回答