当 Apache 通过 PHP PDO 执行超过 5-6 个查询时,它会在 MSSQL 中被另一个进程暂停,从而导致超时

当 Apache 通过 PHP PDO 执行超过 5-6 个查询时,它会在 MSSQL 中被另一个进程暂停,从而导致超时

我会尽量详细。
到目前为止,我只使用 Stack Overflow 和其他类似的网站,但从未发过帖子。我总是能找到问题的答案。但这次不行。

我有一个 Mu Online 游戏服务器,并且运行良好。该服务器的一部分是一个名为“JoinServer”的程序。当我使用非 md5 版本时,它很好,但我想使用文件的 md5 版本。

使用 md5 版本时,我遇到了以下问题:
服务器启动、运行,一切都很正常,直到有人连接到游戏(此时正在创建查询并开始加载 MSSQL)。在此之前,Apache 的查询速度非常快,没有延迟,一切都运行完美。但是当有人连接时(当 JoinServer 开始运行时),锁定开始发生。这仅在 md5 版本的 JoinServer 中持续存在。

我提到了 md5 但没有给出细节,因为我认为我应该说,如果有一点点机会 md5 涉及到整个情况。

游戏运行良好,但是当我通过 Apache 调用超过 5-6 个查询时,Apache 进程会被锁定,并且状态SUSPENDED在 MSSQL 资源监视器中。

这里的问题是:如何防止 Apache 中止?
- 是否可以在 MSSQL 服务器中对进程 (Apache) 进行优先级排序?
- 是否可以防止进程锁定另一个进程(防止 JoinServer 锁定/暂停 Apache 的进程)?
- 我的 Web 查询是否编写得不好,它们会产生过多负载,而 MSSQL 会暂停它们?主观上,它们不会太多,也不会在 SQL 服务器上产生很大的负载。当游戏服务器处于离线状态时,它们会立即运行。
- 无法更改游戏服务器 (JoinServer) 查询,我无法访问其源代码

使用的软件
- Windows Server 2012 R2(在 Windows 7 Pro 上试用过 - 相同)
- Microsoft SQL Server 2008(在 2012 上试用过 - 相同)
- PHP 7.3 通过 xampp 7.3.10
- Ubuntu 上的 PHP 7.3 和 Apache(相同)
- PHP 7.3 的 PDO 官方 Microsoft 驱动程序

以下是我建立数据库连接的方法:

$dsn = 'sqlsrv:server='.Config::DB_SERVER.';Database='.Config::DB_NAME;
$dsn_web = 'sqlsrv:server='.Config::DB_SERVER.';Database=ANHIWEB';
$options = [
                PDO::ATTR_EMULATE_PREPARES   => false,
                PDO::ATTR_ERRMODE            => PDO::ERRMODE_WARNING,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'
                ];

try {

    $db = new PDO($dsn, Config::DB_USER, Config::DB_PASS, $options);
    $webdb = new PDO($dsn_web, Config::DB_USER, Config::DB_PASS, $options);

}

catch (PDOException $e) {
    die(print_r($e->getMessage()));
}

(我正在使用 2 个数据库)。

以下是 PHP 通过 PDO 运行查询的示例:

//Get online players count
$exec = $db->prepare("SELECT count(memb___id) FROM MEMB_STAT WHERE ConnectStat='1'");
    $exec->execute();
    $result = $exec->fetchAll();
    return @$result[0][''];
//Some rankings
    $exec = $db->prepare("SELECT
    RowNum
      ,C.[AccountID]
      ,[CharacterName]
      ,C.[Class]
      ,C.[cLevel]
      ,C.[Resets]
      ,[Point]
FROM    ( SELECT    ROW_NUMBER() OVER ( ORDER BY C.Class DESC ) AS RowNum, *
          FROM      [EVENT_INFO] as E
          WHERE C.ctlCode=0
        ) AS RowConstrainedResult
         left join Character as C ON CharacterName = Name

WHERE   RowNum >= $start
    AND RowNum < $limit
ORDER BY RowNum");

    $exec->execute();
    $result = $exec->fetchAll();
//Get total accounts
    $exec = $db->prepare("SELECT count(memb_guid) FROM MEMB_INFO");
    $exec->execute();
    $result = $exec->fetchAll();
    return @$result[0][''];

编辑:我发现这个查询是锁定的,似乎 JoinServer 使用了表 MEMB_STAT。
这可能是唯一一个锁定的查询。

//Get online players
global $db;
    $exec = $db->prepare("SELECT count(memb___id) FROM MEMB_STAT WHERE ConnectStat='1'");
    $exec->execute();
    $result = $exec->fetchAll();
    return @$result[0][''];

现在的问题是:如何在不引起锁定的情况下选择该计数?

我没有做任何事情来关闭/清理连接,因为我在网上看到说这不是必要的,而且 PHP/PDO 会自行管理,不会有问题。

我的努力:
- 在 Windows 中禁用 IPv6
- 在 SQL 服务器上禁用命名管道
- 尝试并行性 - 没有成功
- 尝试使用 Windows 7,其他一切相同 - 没有成功
- 尝试在 Windows 上运行 Ubuntu 上的 Apache - 没有成功
- 尝试使用 MSSQL 2012 而不是 2008 - 相同

以下是我所获得的有关锁的一些详细信息:
- 任务状态:SUSPENDED
- 命令:SELECT - 应用程序:Apache HTTP Server
- 等待时间(毫秒):(115163增加)
- 等待类型:(LCK_M_S我在谷歌上搜索过,没用)
- 等待资源:keylock hobtid=*** dbid=* id=** and so on
- 被 ID 锁定:204(这是 JoinServer 的 ID)

还有什么可做的?有什么建议吗?

答案1

尝试prepare("SELECT count(memb___id) FROM MEMB_STAT with (nolock) WHERE ConnectStat='1'");但查找有关 nolock 的文档,它有缺点,但我猜对于这个目的它们是可以接受的。https://stackoverflow.com/questions/686724/what-is-with-nolock-in-sql-server

相关内容