7

设置

在这种情况下,我正在使用 php 和 mysql。

假设我有这样的mysqli连接:

$link = new mysqli('localhost', 'root', 'password', 'A_Database');

我已安装 mysqlnd 以使用“MYSQL_ASYNC”参数执行异步 mysql 查询:

$link->query("INSERT INTO `A_Table` VALUES('stuff!')", MYSQLI_ASYNC);

目标

我只想插入一条记录,直到遥远的将来我才需要检索它,所以我不关心异步查询完成需要多长时间,我不需要执行一些 final当我知道查询完成时采取行动。一旦我通过了插入查询发生的代码部分,我确实需要执行其他不相关的 mysql 查询。

问题

执行这样的查询将阻止脚本中稍后出现不同步错误的其他查询。为了解决这个问题,我必须在每个异步查询之后添加类似以下代码:

$links = $errors = $reject = array($link);
if ($link->poll($links, $errors, $reject, 1)) {
    foreach ($links as $resultLink) {
        if ($result = $resultLink->reap_async_query()) {
            if (is_object($result)) {
                $result->free();
            }
        }
    }
}

这有效地阻止了不同步错误,并且我的代码工作正常。
不过,有两件事仍然困扰着我:

  1. 我不想为此烦恼,因为我只执行插入查询,当我知道插入完成时,我不关心在我的代码中有一些响应。

  2. 轮询代码在我的服务器上运行得非常慢;比执行常规查询和同步获取结果要慢得多。

回顾

我想以两个要求运行插入查询;该查询是非阻塞的(异步的),稍后我仍然可以执行其他 mysql 查询。我只想插入查询并“忘记它”,然后继续我的代码。

有什么建议最好的方法是什么?

4

2 回答 2

7

如果您的目标是插入一条记录并继续执行代码而不担心结果,您可以使用INSERT DELAYED语法而无需 ASYNC 标志:

$link->query("INSERT DELAYED INTO `A_Table` VALUES('stuff!')" );

它会立即返回,您可以继续在同一连接上执行新查询。我们在我们的日志系统上使用它。

于 2015-07-24T02:15:21.190 回答
4

如果您希望能够触发并忘记您的查询,那么您当前的方法大多是正确的,尽管我建议您遇到的缓慢可能是因为您将 '1' 设置为$link->poll($links, $errors, $reject, 1). 这意味着轮询将等待最多 1 秒以等待查询返回。如果将其设置为“0”,则它不会等待,它会更快地返回查询是否完成的答案。

其次,如果您不需要此查询的答案,您可以在执行此查询时做其他事情,如果您有其他事情,您不必坐在那里等待它在异步轮询循环中返回继续前进。这就是 ASYNC 查询的设计目的。我建议您在查询执行方法中添加检查以检查是否已经执行了未完成的 ASYNC 查询,因此每当您需要启动新查询时,它才会轮询服务器并等待任何先前的查询完成并变得可用。

或者,如果您想运行多个相互之间没有任何影响或依赖的查询,则没有什么可以阻止您设置多个数据库连接并在所有这些连接上并行运行 ASYNC 查询,或者设置新连接并执行在需要时查询。

如果您想将您的 SQL 完全外包给另一个进程(没有 cron),一种方法是设置一个持久监控脚本,例如使用Supervisor / Gearman,这样您就可以向它发送查询并让它在一个进程中处理查询(甚至服务器)与本地不同。这样做的好处是远程脚本作为 CLI 应用程序执行,因此具有更多使用分叉多线程处理的能力,并且可以在暴露较少的环境中运行。

另一种方法(可选使用 cron)是使用写优化(可能在内存中)本地数据库表,在该表中快速执行插入,然后让另一个进程间歇性地读取该表(或设置触发器以监视新的条目),并让该进程从该表中获取新插入的行并将它们移动到速度较慢的主表中。

于 2014-11-19T10:23:52.967 回答