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