ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2019-11-21 10:15:55  阅读:255  来源: 互联网

标签:large-data-volumes repeat mysql 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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有