Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何处理/优化数千个不同的选择查询?_Php_Mysql_Sql Server_Pdo - Fatal编程技术网

Php 如何处理/优化数千个不同的选择查询?

Php 如何处理/优化数千个不同的选择查询?,php,mysql,sql-server,pdo,Php,Mysql,Sql Server,Pdo,我需要在两个数据库(一个是mysql,另一个是远程托管的SQL Server数据库)之间同步数千行的特定信息。当我执行这个php文件时,我想它会在几分钟后卡住/超时,因此我想知道如何解决这个问题,并可能优化“同步”它的方式 代码需要执行的操作: 基本上,我希望从另一个SQL Server数据库中获取数据库中更新的每一行(=一个帐户)-两条特定信息(=2SELECTquerys)。因此,我使用一个foreach循环,它为每一行创建两个SQL查询,然后将这些信息更新到此行的两列中。我们讨论需要通过该

我需要在两个数据库(一个是mysql,另一个是远程托管的SQL Server数据库)之间同步数千行的特定信息。当我执行这个php文件时,我想它会在几分钟后卡住/超时,因此我想知道如何解决这个问题,并可能优化“同步”它的方式

代码需要执行的操作:

基本上,我希望从另一个SQL Server数据库中获取数据库中更新的每一行(=一个帐户)-两条特定信息(=2
SELECT
querys)。因此,我使用一个foreach循环,它为每一行创建两个SQL查询,然后将这些信息更新到此行的两列中。我们讨论需要通过该foreach循环的~10k行

我的主意哪一个可能有用

我听说过PDO事务之类的事情,它应该收集所有这些查询,然后在所有
SELECT
查询的包中发送它们,但我不知道我是否正确使用它们,或者它们在这种情况下是否有帮助

这是我当前的代码,几分钟后超时:

// DBH => MSSQL DB | DB => MySQL DB
$dbh->beginTransaction();
// Get all referral IDs which needs to be updated:
$listAccounts = "SELECT * FROM Gifting WHERE refsCompleted <= 100 ORDER BY idGifting ASC";
$ps_listAccounts = $db->prepare($listAccounts);
$ps_listAccounts->execute();

foreach($ps_listAccounts as $row) {
    $refid=$row['refId'];
    // Refsinserted
    $refsInserted = "SELECT count(username) as done FROM accounts WHERE referral='$refid'";
    $ps_refsInserted = $dbh->prepare($refsInserted);
    $ps_refsInserted->execute();
    $row = $ps_refsInserted->fetch();
    $refsInserted = $row['done'];

    // Refscompleted
    $refsCompleted = "SELECT count(username) as done FROM accounts WHERE referral='$refid' AND finished=1";
    $ps_refsCompleted = $dbh->prepare($refsCompleted);
    $ps_refsCompleted->execute();
    $row2 = $ps_refsCompleted->fetch();
    $refsCompleted = $row2['done'];

    // Update fields for local order db
    $updateGifting = "UPDATE Gifting SET refsInserted = :refsInserted, refsCompleted = :refsCompleted WHERE refId = :refId";
    $ps_updateGifting = $db->prepare($updateGifting);

    $ps_updateGifting->bindParam(':refsInserted', $refsInserted);
    $ps_updateGifting->bindParam(':refsCompleted', $refsCompleted);
    $ps_updateGifting->bindParam(':refId', $refid);
    $ps_updateGifting->execute();
    echo "$refid: $refsInserted Refs inserted / $refsCompleted Refs completed<br>";
}

$dbh->commit();
//DBH=>MSSQL数据库| DB=>MySQL数据库
$dbh->beginTransaction();
//获取所有需要更新的转诊ID:

$listAccounts=“SELECT*FROM Gifting WHERE refsCompleted您可以通过一个相关子查询在一个查询中完成所有这些操作:

UPDATE Gifting
SET
    refsInserted=(SELECT COUNT(USERNAME)
                    FROM accounts
                    WHERE referral=Gifting.refId),
    refsCompleted=(SELECT COUNT(USERNAME)
                    FROM accounts
                    WHERE referral=Gifting.refId
                        AND finished=1)
相关子查询本质上是使用子查询(查询中的查询)这引用了父查询。请注意,在每个子查询中,我都引用了每个子查询的where子句中的
Gifting.refId
列。虽然这对性能不是最好的,因为每个子查询仍然必须独立于其他查询运行,但它的性能会更好(而且可能和你将得到的一样好)比你在那里拥有的还要多

编辑:

仅供参考。我不知道一笔交易在这里是否有帮助。通常,当您有几个相互依赖的查询时,会使用这些查询,并在其中一个查询失败时为您提供回滚的方法。例如,银行交易。在插入购买之前,您不希望余额扣除一些金额。如果购买由于某种原因,您希望回滚对余额的更改。因此,在插入采购时,您启动一个事务,运行更新余额查询和插入采购查询,并且只有在两者都正确进入并经过验证后,您才提交保存

编辑2:

如果我这样做,而不进行导出/导入,这就是我要做的。不过,这需要做一些假设。首先,您使用的是mssql 2008或更高版本,其次,引用id始终是一个数字。我还使用一个临时表,在其中插入数字,因为您可以通过一个查询和n运行单个更新查询以更新礼品表。此临时表遵循结构
CREATE table tentable(refId int、done int、total int)

//获取推荐帐户列表
//如果使用的是一列,则只查询一列

$listAccounts=“SELECT DISTINCT refId FROM Gifting WHERE refs completed您的2个SELECT FROM accounts应滚入1这似乎可以全部滚入一个更新查询中。与一个查询中的所有行和更新一样。如何将这2个选择添加到一个查询中?两个查询都是不同的数字(一个查询将给出一个订单的插入金额-例如,一个订单有100个包裹,另一个查询将给出已完成/已发送包裹的金额)有两个问题,refId总是一个数字,还是可以在其中包含字母?我需要知道是否应该在字符串周围添加引号。第二个问题是您使用的sql server版本是什么?refId总是一个varchar-示例数据:“5447f1618d30839522552”-sql server是两个数据库之间的2012Um(一个是mysql,另一个是mssql)”。我想问题是我使用的是两个完全不同的数据库(一个是远程托管的mssql数据库)。但基本上我得到了这个优化,它将帮助我思考,但这还不能解决我的问题:(.通过阅读代码,我没有注意到更新的数据库与select语句不同。我将根据我的建议更新我的答案。感谢更新,我将仔细检查代码并进行测试!
//get list of referral accounts
//if you are using one column, only query for one column
$listAccounts = "SELECT DISTINCT refId FROM Gifting WHERE refsCompleted <= 100 ORDER BY idGifting ASC";
$ps_listAccounts = $db->prepare($listAccounts);
$ps_listAccounts->execute();

//loop over and get list of refIds from above.
$refIds = array();
foreach($ps_listAccounts as $row){
    $refIds[] = $row['refId'];
}


if(count($refIds) > 0){
    //implode into string for use in query below
    $refIds = implode(',',$refIds);

    //select out total count
    $totalCount = "SELECT referral, COUNT(username) AS cnt FROM accounts WHERE referral IN ($refIds) GROUP BY referral";
    $ps_totalCounts = $dbh->prepare($totalCount);
    $ps_totalCounts->execute();

    //add to array of counts
    $counts = array();

    //loop over total counts
    foreach($ps_totalCounts as $row){
        //if referral id not found, add it
        if(!isset($counts[$row['referral']])){
            $counts[$row['referral']] = array('total'=>0,'done'=>0);
        }
        //add to count
        $counts[$row['referral']]['total'] += $row['cnt'];
    }

    $doneCount = "SELECT referral, COUNT(username) AS cnt FROM accounts WHERE finished=1 AND referral IN ($refIds) GROUP BY referral";
    $ps_doneCounts = $dbh->prepare($doneCount);
    $ps_doneCounts->execute();

    //loop over total counts
    foreach($ps_totalCounts as $row){
        //if referral id not found, add it
        if(!isset($counts[$row['referral']])){
            $counts[$row['referral']] = array('total'=>0,'done'=>0);
        }
        //add to count
        $counts[$row['referral']]['done'] += $row['cnt'];
    }

    //now loop over counts and generate insert queries to a temp table.
    //I suggest using a temp table because you can insert multiple rows
    //in one query and then the update is one query.
    $sqlInsertList = array();
    foreach($count as $refId=>$count){
        $sqlInsertList[] = "({$refId}, {$count['done']}, {$count['total']})";
    }

    //clear out the temp table first so we are only inserting new rows
    $truncSql = "TRUNCATE TABLE tempTable";
    $ps_trunc = $db->prepare($truncSql);
    $ps_trunc->execute();

    //make insert sql with multiple insert rows
    $insertSql = "INSERT INTO tempTable (refId, done, total) VALUES ".implode(',',$sqlInsertList);
    //prepare sql for insert into mssql
    $ps_insert = $db->prepare($insertSql);
    $ps_insert->execute();

    //sql to update existing rows
    $updateSql = "UPDATE Gifting
                    SET refsInserted=(SELECT total FROM tempTable WHERE refId=Gifting.refId),
                        refsCompleted=(SELECT done FROM tempTable WHERE refId=Gifting.refId)
                    WHERE refId IN (SELECT refId FROM tempTable)
                        AND refsCompleted <= 100";
    $ps_update = $db->prepare($updateSql);
    $ps_update->execute();
} else {
    echo "There were no reference ids found from \$dbh";
}