如何定期更新数据库表的小部分


How to rutinely update a database table in small portions

<?php
require_once( dirname(__FILE__) . '/shared.php');
function tabelle_holen_hosters( $condition = "" ) {
    global $wpdb;
    $sql = "SELECT * FROM whatever" . $condition;
    if( $table = $wpdb->get_results( $sql, ARRAY_A ) ) {
        return $table;
    } else {
        echo "SQL ERROR in tabelle_holen()";
        var_dump( $table );
        return false;
    }
}
$test = tabelle_holen_hosters( " WHERE working=1 AND alexacheck=0 LIMIT 200" );
?>
<table>
<tbody>
<?php
foreach ( $test as $row ){
    $rank = (int) alexaRank( $row['hoster'] );
    if ($rank == 0)
        $rank = 999999999;
    echo '<tr>';
    echo '<td>' . $row['hoster_id'] . '</td>';
    echo '<td>' . $row['hoster'] . '</td>';
    echo '<td>' . $rank . '<td>';
    echo '</tr>';
    $wpdb->update(
    'fhw_filehosters',
        array(
            'alexa' => $rank,
            'alexacheck' => 1
        ),
        array( 'hoster_id' => $row['hoster_id'] ),
        array(
            '%d',
            '%d'
        ),
        array( '%d' )
    );
    flush(); // <----- NOT working.
}
?>
</tbody>
</table>
<?php
function alexaRank( $url ) {
    $request_url = "http://data.alexa.com/data?cli=10&url=".$url;
    $xml = simplexml_load_file($request_url) or die("feed not loading");
    return $xml->SD->POPULARITY['TEXT'];
}
我有这个脚本,我使用wordpress数据库类没有wordpress。我将行限制为200,因为否则我会遇到像页面加载需要数年的问题,也许php执行时间从alexa函数的xml需要很长时间。数据库中有很多url需要检查,我想用一个动作全部更新,也就是删除200限制。我要怎么做才能让它一次做50个,然后输出,然后继续?Ajax吗?我该怎么做呢?更新1:

正如我在评论中所说的,我正在寻找一些东西来使这种情况发生(在后台)我的网站,我实际上不太确定是否涉及php执行时间限制在这一点上,但对于"一次性"的解决方案,我只是在队列结束时测试了flush(),它不工作!

但是我正在寻找一个例程函数,现在我更新了问题,答案是非常通用的,我不是那个经验。我很想看到一些实际的代码。如果这太多了,并倾向于"给我写一个程序",那么我必须通过挖掘一些时间来弄清楚这一点。那么我就接受最有效的答案。

您的直接问题(如何在脚本运行时开始输出)很容易回答:

flush();

但是如果PHP的执行时间限制了你,那么这并不能解决你的问题。那么剩下的就是AJAX:

  • 将脚本分成两个文件:一个带有空<table>和JavaScript,另一个将通过AJAX调用,执行实际处理并返回表行。
  • 像这样限制处理的行数:LIMIT $start, 50,其中$start通过GET/POST参数
  • 提供
  • 在JavaScript中,首先调用start=0的PHP脚本,然后在处理完响应后,再次调用start增加50。重复,直到响应为空。

首先将工作与基础和前端代码分开,所以:

  1. ajax.getdata.php//这里我们根据给定的参数获取数据

    $page = $_GET["page"]; // I skip the validation, you should do it be yourself
    require_once( dirname(__FILE__) . '/shared.php');
    function tabelle_holen_hosters( $condition = "" ) {
        global $wpdb;
        $sql = "SELECT * FROM whatever" . $condition;
        if( $table = $wpdb->get_results( $sql, ARRAY_A ) ) {
            return $table;
        } else {
            echo "SQL ERROR in tabelle_holen()";
            var_dump( $table );
            return false;
        }
    }
    function alexaRank( $url ) {
        $request_url = "http://data.alexa.com/data?cli=10&url=".$url;
        $xml = simplexml_load_file($request_url) or die("feed not loading");
        return $xml->SD->POPULARITY['TEXT'];
    }
    $limit = 200;
    $start= $page*$limit;
    $test = tabelle_holen_hosters( " WHERE working=1 AND alexacheck=0 LIMIT $start,$limit" );
    
     $str = '<table>';
    foreach ( $test as $row ){
        $rank = (int) alexaRank( $row['hoster'] );
        if ($rank == 0)
            $rank = 999999999;
        $str.= '<tr>';
        $str.= '<td>' . $row['hoster_id'] . '</td>';
        $str.= '<td>' . $row['hoster'] . '</td>';
        $str.= '<td>' . $rank . '<td>';
        $str.= '</tr>';
        $wpdb->update(
        'fhw_filehosters',
            array(
                'alexa' => $rank,
                'alexacheck' => 1
            ),
            array( 'hoster_id' => $row['hoster_id'] ),
            array(
                '%d',
                '%d'
            ),
            array( '%d' )
        );
    }
    $str.='</table>';
    echo $str;
    exit;
    ?>
    

  2. index.html//构建前端视图,并向服务器发送ajax请求。

    <div id="content">
    </div>
    <div id="controls">
    <span onCLick="goPrev()">
    Prev
    </span>
    <span onCLick="goNext()">
    Next
    </span>
    </div>
    <script>
    var page=0;
    //this functions can be moved to separate file
    function goNext(){
    page++;
    //here should be some limit for max page
    readData();
    }
    function goPrev(){
    if(page==0) return false;
    page--;
    readData();
    }
    function readData(){
    $.ajax({
    "url":"/path/to/ajax.getdata.php?page="+page,
    }).done(function(data){
    $("#content").html(data);
    });
    }
    readData();
    </script>
    </body>
    </html>
    

所以现在你可以定义自己有多少记录在一个时间你会显示,并可以去下一页或上一页的控制点击。

如果你只是想更新行,你想知道哪些项目被更新了,你不需要一个web服务器。您可以使用logger -> KLogger将更新信息写入磁盘,而不是'echo'。在这种情况下,使用PHP CLI具有优势。可以设置max_execution_time(0)并增加memory_limit。此外,我认为它比使用apache或nginx快一点。你想批量更新吗?看看这篇文章。或者,您可以使用MySQL。如果在工作和alexacheck上有很多不同的状态,不要忘记对它们进行索引。

像这样长时间运行的进程可能是作业队列的候选者。

  1. 一次将50个url排队到一个队列。
  2. 让每个作业队列worker在完成后将结果发送到主应用程序。
  3. 你的应用程序将在结果从队列进入时处理结果的显示。

这些都应该异步完成。

当应用程序进入"维护"模式时。您仍然可以使用相同的作业队列。就像前面提到的一个评论一样,您甚至可以有一个cron作业,它每天向队列发送两次作业。

你应该这样考虑:

  • 创建一个大的上帝母亲循环。
  • 保留一个$total计数器和一个$temp计数器。
  • 循环迭代100 (n)次,每次增加计数器。
  • 一旦你达到100个数字限制(或50或200或其他),你重置温度计数器。
  • 你让程序进入睡眠3秒(或类似的东西)。
  • 你再次迭代n次temp变量,但你请求的数据与$total计数器相对应。

  • 创建一个大的上帝母亲循环。
  • 有一个计数器
  • 在每次循环迭代中增加计数器。
  • 一旦计数器达到你定义的最大值,你重置它。睡眠
  • 重复。

都有利润

现在,由于您需要一些代码和一些解释:

PHP手册说:

int sleep ( int $seconds )
"Delays the program execution for the given number of seconds."

所以程序的执行是延迟的,如果你延迟了执行时间,你就不能达到限制。

你可以这样写:

$i = 0;
$max = 50;
$sleepTime = 3;
foreach ( $test as $row ){
    $rank = (int) alexaRank( $row['hoster'] );
    if ($rank == 0)
    $rank = 999999999;
    echo '<tr>';
    echo '<td>' . $row['hoster_id'] . '</td>';
    echo '<td>' . $row['hoster'] . '</td>';
    echo '<td>' . $rank . '<td>';
    echo '</tr>';
    $wpdb->update('fhw_filehosters', array(
        'alexa' => $rank,
        'alexacheck' => 1
    ),
    array(
        'hoster_id' => $row['hoster_id']
    ),
    array(
        '%d',
        '%d'
    ),
    array( '%d' )
    );
    ii($i === $max)
    {
        $i = -1;
        sleep($sleepTime);
    }
    $i++;
}

至少尝试一下,最好的学习方法是实验。

我通常使用ob_start和ob_flush函数。

另一种思考方式是:是否只能为访问站点的单个用户更新某些行?为了给人一种正在更新的错觉。

在网络浏览器游戏中,这种情况非常普遍。它们给人一种一切都是最新的错觉,但实际上只是玩家的信息被更新了。

或者你可以看看你的服务器主机是否有一个"预定脚本"的选项,我知道一些允许这样做。它将触发脚本在一天的间隔或特定时间运行。