如何为查询执行设置语句超时
在我的网页应用中,有些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 及以上版本现在有了一个事件系统……可能会有类似的功能。可以查看一下: