编程语言
首页 > 编程语言> > php-如何查询,然后在较短的时间内处理大量

php-如何查询,然后在较短的时间内处理大量

作者:互联网

我有一张大桌子的订单.在设定的时间,我需要向他们的一大块发送一条SMS消息(不幸的是,每个消息的内容不同)(基于他们是否选择了该消息以及是否包含电话号码).在相当短的时间内它可能是200,000个数字. (现在还不算高,但是从理论上讲可以并希望如此构建).

它们并不需要全部立即发送,但是-在设定时间的1-3小时内是理想的选择.

我正在使用带有API的服务来发送它们,所以这不是问题-问题是:

1)如何处理大量

2)如何知道它们都已处理或重新处理了未处理的

我认为执行MySQL查询以获取所有200,000个电话号码然后循环浏览不是一个好主意-我必须假设这会占用大量内存(?).

所以-我想尝试一项cron作业,并使其每分钟(或大约)运行一次.在该脚本中,我可以提取5,000条记录,标记为“处理中”,然后重复处理每个记录,然后将其行更新为“已发送”.

但这有很多潜在的问题……如果SMS服务变慢而我不能全部发布,该怎么办.如果出现无法预料的错误并且脚本在途中停止运行…等等.如果有任何原因导致该脚本无法发送全部5000条记录,我怎么知道该返回哪些记录并重新处理?

这不仅是此过程,还有其他一些过程-整个问题不断浮出水面,即如何处理需要以某种方式处理的大量行并知道每个行都已完成.

我希望我只是使这些废话变得过于复杂,并且有一些更简单的处理方法.

如果我不清楚,请发表评论,我很乐意进一步解释任何方面.

解决方法:

简短版本:

>不用担心内存消耗.只是不要尝试立即获取整个结果集.
>您的想法是使用一个单独的表来列出每个文本消息,然后在知道该行是否成功时更新该行,这通常是正确的方法(无论您是否使用cron都没有关系).
>如果您担心SMS提供商可能会丢弃某些请求,则可以使用a ActiveMQ或类似的方法实现自己的排队机制.但是,这种方式在很大程度上削弱了使用提供程序的目的.他们应该使用自己的队列,以便您不必担心.

细节:

SMS服务应通知您成功或失败.
大多数高容量SMS服务将您的消息排队,然后一次以n条消息的块发送出去.然后,他们将通过某种回调或Web挂钩通知您哪些消息成功,哪些消息失败.
它们中的大多数还提供API,可让您检查是否已发送某些消息.您需要利用这些功能.

我认为您的Cron方法正走上正确的道路.

一种选择是永不“拉”记录.而是在现有表上有一列,以指定是否正在等待消息的发送.这样,您无需执行SELECT并处理成千上万的行,而是执行简单的UPDATE,然后当每个回调都来自API时,您可以成功/失败地重新更新行.

如果您可能一次为每行数据发送多个消息,那么显然这是行不通的.您将必须有一个单独的表,其中每个要跟踪的消息都带有一行.

至于您的内存问题,我认为这不是问题.只是不要获取整个结果集.相反,请分别获取每一行.这将防止mysql返回整个数据集,因此您无需将其保存在内存中.

来自php.net

As mysqli_fetch_all() returns all the rows as an array in a single step, it may consume more memory than some similar functions such as mysqli_fetch_array(), which only returns one row at a time from the result set. Further, if you need to iterate over the result set, you will need a looping construct that will further impact performance. For these reasons mysqli_fetch_all() should only be used in those situations where the fetched result set will be sent to another layer for processing.

> mysqli fetch_all docs
> mysqli fetch_array docs

编辑/修改

解决评论/问题:

I can’t pull just one entry per chron – that would take forever… I
understand I shouldn’t fetch the entire result set at once too, that’s
what led me to ask “then how else can I do it?

在PHP中(将mysqli与mysqlnd结合使用),当您执行查询时,它实际上并不返回数据.它根据您的查询准备要返回的数据,但不会返回.

当您使用fetch_all时,您要求的是整个结果.
当您使用fetch_array时,您要求的是下一个结果,并且您告诉mysql移动结果光标,以便在此之后可以获得下一个结果.只要您不将每个结果存储在内存中(使用单独的变量),就不会出现内存问题.只需在需要时使用该行,然后获取下一行即可.
不管是cron工作,都没有关系.
您无需一遍又一遍地调用脚本,每行一次.该脚本在一次调用中处理每一行.它只是一次读取一行,以节省内存.

这是一个脚本示例:

$mysqli = new mysqli("host", "user", "pass", "db");
$query = "SELECT * from TextMessages";
$result = $mysqli->query($query);
while ($row = $mysqli->fetch_array($result))
{
    //this is the only thing you store in memory, one single row at a time
    $row = $result->fetch_array(MYSQLI_ASSOC);

    //go send the text message and do whatever else you need to do
    if ($row["SomeSmsToken"] == null && $row["TextHasAlreadyBeenSentOrDateSentOrWhatever"] == false)
    {
        //$someSmsToken = $myTwilioObject->SendByRow($row);
        //$this->UpdateRowToTellItThatItHasBeenSentToProviderAndIsWaitingForResponse($row,$someSmsToken);
        //..etc...
        //then go to the next row.
    }
}
$result->free();

然后在某些回调脚本中,您将执行以下操作.

$mysqli = new mysqli("host", "user", "pass", "db");
$query = "SELECT * from TextMessages where SomeSmsToken = '".$_POST["SomeTokenSentFromProviderInCallback"]."'";
$result = $mysqli->query($query);
while ($row = $mysqli->fetch_array($result))
{
  $someObject->UpdateRowToSayThatTheTextWasSentOrItFailed($row,$_POST["SomeStatusSentFromProviderInCallback"]);
}

$result->free();

完成后,您还可以使用mysqli_free_result,以通过php的mysql驱动程序释放所有消耗的内存.

从php.net:

You should always free your result with mysqli_free_result(), when your result object is not needed anymore.

编辑:
如果您想要某种聪明的方式来处理“脚本超时的情况”,我建议每分钟运行一次cron.
当它运行时,应检查它是否已在运行,如果尚未运行,则应运行它.
该脚本将一直有效,直到超时.
然后在一分钟之内,cron将再次启动它,由于它没有在运行,因此它将再次运行并在中断的地方继续运行.

标签:large-data-volumes,repeat,mysql,php
来源: https://codeday.me/bug/20191121/2051052.html