循环执行10,000次查询的最佳方法是什么?

4

在进行大循环时,我经常遇到PHP的问题。当我们处理大量数据时,我会将其拆分为非常小的循环,并重复执行这些循环几百次。

下面是我目前正在处理的一个示例:

$stmt = $GLOBALS['link']->prepare('SELECT * FROM tracking_redirect');
$stmt->execute();
$tracking = new tracking();
while($click = $stmt->fetch()){
    $tracking->checkClickIP($click['blogid'], $click['campaignid'], $click['id'], $click['ipaddress']);
}

tracking_redirect是一个包含关于用户被重定向到哪个网站的大量信息的表格。我会保存一些数据,例如IP地址,cookie数据,日期和用户ID。该表格目前已经有约60,000行。

checkClickIP()是一个用来检查点击/重定向是否合法或有效的函数。比如用来确保同一个用户不会点击太多次。

public function checkClickIP($userid, $campaignid, $clickid, $ipaddress = null) {
        if(!isset($ipaddress)){
            $ipaddress = $_SERVER['REMOTE_ADDR'];
        }

        $datestmt = $GLOBALS['link']->prepare('SELECT crdate FROM tracking_redirect WHERE id=:clickid');
        $datestmt->execute(array('clickid' => $clickid));
        $datestmt = $datestmt->fetch();

        $stmt = $GLOBALS['link']->prepare('SELECT COUNT(*) as total FROM tracking_redirect WHERE ipaddress=:ipaddress AND campaignid=:campaignid AND blogid=:userid AND crdate<:clickdate');
        $stmt->execute(array(
            'ipaddress' => $ipaddress, 
            'campaignid' => $campaignid, 
            'userid' => $userid, 
            'clickdate' => $datestmt['crdate']
        ));
        $totalclicks = $stmt->fetch();

        //Same computer has clicked more than 5 times on the same campaign. ALERT WARNING!
        if($totalclicks['total'] >= 5){
            //Disable the click
            $disable = $GLOBALS['link']->prepare('UPDATE tracking_redirect SET disabled=:disabled WHERE id=:clickid');
            $disable->execute(array(
                'disabled' => 1, 
                'clickid' => $clickid
            ));

            //Send a warning to the user if this person clicked 5 times on the same campaign.
            if($totalclicks['total'] == 5){
                $stmt = $GLOBALS['link']->prepare('SELECT * FROM user_login_history WHERE userid=:userid AND usertype=:usertype AND ipaddress=:ipaddress AND date(visitdate) BETWEEN :startdate AND :currentdate LIMIT 1');
                $stmt->execute(array(
                    'userid' => $userid, 
                    'usertype' => 1, 
                    'ipaddress' => $ipaddress, 
                    'startdate' => date('Y-m-d', strtotime('-3 months')), //If user logged in 3 months ago or closer from this IP
                    'currentdate' => date('Y-m-d')
                ));
                //The computer belongs to the blogger who published the ad. ALERT WARNING! USER CLICKING HIS OWN ADS
                if($loginhistory = $stmt->fetch()){
                    //Send warning to user.
                }
                //The computer does not belong to the blogger, but it's suspicious behavior. ALERT WARNING! CHECK POST
                else{
                    //Send warning to user.
                }
            }
        }
    } 

我知道在While循环外准备语句更好。但我仍然希望能够使用函数并编写干净的代码。这段代码只是一个例子,我无法运行while循环,因为服务器会超时等问题导致出错。

所以,请不要过于关注此案例中的细节。而是请提供可应用于其他代码的一般信息。我该怎么做才能使这种循环可以执行大约10,000或100,000次?


什么阻止你运行如此大的循环?当您从命令行启动PHP时,没有超时,脚本可以运行所需的时间。 - Gerald Schneider
你考虑过使用存储过程吗? - Kami
1个回答

3
这在处理大量数据时总是一个问题。我目前正在开发的产品中,有时会在一个操作中更新20K条记录。软件的另一部分使用简单的LINQ查询,但只要需要上传、更新或获取批量数据,我们就会使用存储过程。
在这方面,您可能想查看这个链接MySQL存储过程 vs. 复杂查询

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接