Django:如何防止长查询杀死数据库?
我正在使用Django 1.1和Mysql 5.*,并且使用的是MyISAM表。
我的一些查询在处理数据集中的极端值时可能会花费很长时间。这会导致表被锁住,网站也会因此瘫痪。有时候,似乎有些用户在请求完成之前就取消了请求,这样一些查询会卡在“准备”阶段,导致其他查询无法执行。
我打算找出所有可能的问题,但有一个安全措施可以防止网站崩溃是很好的。
我该如何避免这种情况?我可以设置查询的最大时间吗?
6 个回答
0
你知道什么是查询吗?也许你可以优化一下SQL语句,或者在你的表上加一些索引?
1
我正在做一个Django数据库复制的应用,遇到了同样的问题,当网络延迟增加时,跨广域网的查询有时会卡住。
来自 http://code.activestate.com/recipes/576780/
食谱 576780:为(几乎)任何可调用对象设置超时
创建一个有时间限制的可调用对象版本。
比如说,如果想把函数 f
的执行时间限制为 t 秒,首先要创建一个有时间限制的 f
版本。
from timelimited import *
f_t = TimeLimited(f, t)
然后,不要直接调用 f(...)
,而是用 f_t
来调用,比如:
try:
r = f_t(...)
except TimeLimitExpired:
r = ... # timed out
可以这样使用,例如:
def _run_timed_query(cursor, log_msg, timeout, query_string, *query_args):
"""Run a timed query, do error handling and logging"""
import sys
import traceback
from timelimited import *
try:
return TimeLimited(cursor.execute, timeout)(query_string, *query_args)
except TimeLimitExpired:
logger_ec.error('%s; Timeout error.' % log_msg)
raise TimeLimitExpired
except:
(exc_type, exc_info, tb) = sys.exc_info()
logger_ec.error('%s; %s.' % (log_msg, traceback.format_exception(exc_type, exc_info, None)[0]))
raise exc_type
1
很遗憾,MySQL没有提供简单的方法来解决这个问题。一个常见的做法是写一个脚本,每隔X秒检查一次所有正在运行的进程(X的值取决于你认为的“太长”),然后结束那些运行时间过长的进程。不过,你至少可以通过在MySQL中设置log_slow_queries
来获取一些基本的诊断信息,这样就会把所有运行超过10秒的查询记录到日志里。如果你觉得10秒对你来说太长了,可以把long_query_time
设置成其他值,来改变这个时间限制。