我有一个非常繁重的SQL搜索查询需要几分钟才能完成,从一个由ajax请求调用的PHP脚本调用。
问题是,用户经常会不耐烦地多次点击搜索按钮,每次创建新的ajax请求和新的PHP脚本执行。但旧的继续执行,即使连接已被删除。这会导致SQL Server负载持续处于100%的CPU使用率。
所以我测试了我的理论,即使浏览器选项卡关闭后脚本执行仍在继续。我使用了两种类型的查询,一种即席查询和一种存储过程执行,两种方法都做同样的事情,将数字1-9插入表中,每个数字之间有2秒的延迟。
即席查询:
for($i = 1; $i < 10; $i++){
$sql = "INSERT INTO t (i) VALUES(?)";
$res = pdoQuery($sql, array($i));
if($res === false){
echo $pdo->getErrorMessage();
http_response_code(500);
exit();
}
sleep(2);
}
SP电话:
$sql = "EXEC sp_Slow";
$res = pdoQuery($sql);
if($res === false){
echo $pdo->getErrorMessage();
http_response_code(500);
exit();
}
我如何测试:使用触发ajax调用每个脚本的按钮,我测试了它们,点击按钮并立即关闭标签。然后监控表中的数据。就像我怀疑的那样,新数据每2秒插入一次。 (如果我直接在浏览器中打开脚本并关闭选项卡,而不是通过ajax请求它,也会发生这种情况)
我需要一种方法来在用户断开连接时完全杀死PHP和SQL执行,事务并不重要,因为它只是一个选择操作。
答案 0 :(得分:0)
您可以使用php.ini指令或在运行时使用ignore_user_abort()函数更改此行为。
答案 1 :(得分:0)
这是我所做的,来自@Robbie Toyota的评论,谢谢!
if(!empty($_SESSION['SearchSPID'])){
$sql = "KILL " . $_SESSION['SearchSPID'];
$res = pdoQuery($sql);
if($res === false){
exit('Query error: failed to kill existing spid:' . $_SESSION['SearchSPID']);
}
$_SESSION['SearchSPID'] = null;
}
$sql = "SELECT @@spid AS SPID";
$res = pdoQuery($sql);
$spid = $res->row_assoc()['SPID'];
$_SESSION['SearchSPID'] = $spid;
// do long query here
$_SESSION['SearchSPID'] = null;
当然使用这种方法你必须要小心会话文件锁定,如果发生这种情况会使整个事情变得毫无意义,因为那时请求将是顺序的而不是并行的