我從來沒有過多關注過學說產生的查詢數量,直到今天我有一個相當簡單的任務(或者我認為)運行 750 個查詢 16 秒......
public function indexAction()
{
$em = $this->em;
$risks = $em->getRepository('App\Entity\Hazardlog\Risk')->findAll();
//filter out only risks belonging to a current version analysis
$risksCurrent = array();
foreach($risks as $r) {
if ($r->getAnalysis()->getCurrentVersion() == true) {
$risksCurrent[] = $r;
}
}
return $this->render('risk/index.html.twig', array(
'risks' => $risksCurrent,
));
}
所以我想對于回圈中的每一輪,都會執行一個新的 SQL 查詢。我認為這些物件是在第一次呼叫時全部獲取的,然后它并沒有“花費”我一個資料庫呼叫來訪問這些物件的屬性,但我非常錯誤地=)
有沒有辦法更有效地做到這一點,而無需撰寫好的舊 SQL 查詢?我可以做到
SELECT * FROM risk JOIN analysis ON risk.analysis = analysis.id WHERE (analysis.CurrentVersion = true)
但我寧愿處理物體物件而不是 SQL ......
將控制器更改為...
public function indexAction()
{
$em = $this->em;
$query = $em->createQuery('SELECT * FROM risk JOIN analysis ON risk.analysis = analysis.id WHERE (analysis.CurrentVersion = true)');
$risksCurrent = $query->getResult();
return $this->render('risk/index.html.twig', array(
'risks' => $risksCurrent,
));
}
...在半秒鐘內將其減少到 18 個查詢,這要舒服得多...我的代碼中仍然只看到一個查詢,所以我不知道發生了什么??
uj5u.com熱心網友回復:
Doctrine 默認情況下不查詢關系,僅在需要時才獲取它們。當您的場景有許多相同的查詢發生時,它被稱為N 1 problem. 這里有兩個基本的解決方案如何避免這個問題。
解決方案 1 – 通過映射配置獲取
此解決方案僅在您知道您需要Analysis 始終與您的Risk. 如果您有例如帶有Risk詳細資訊的頁面,那么您不需要訪問Analysis此解決方案的地方可能不是最好的。
例如想象這個物體:
class Risk
{
...
/**
* @ORM\OneToOne(targetEntity=Analysis::class)
*/
private $analysis;
...
}
現在,如果你執行你的代碼,它會遇到同樣的問題。但是如果你添加fetch="EAGER",Doctrine 會在一個查詢中提前獲取所有的分析。
您的物體現在看起來像這樣:
class Risk
{
...
/**
* @ORM\OneToOne(targetEntity=Analysis::class, fetch="EAGER")
*/
private $analysis;
...
}
解決方案 2 – 使用存盤庫和 Doctrine Query Builderjoin
在此解決方案中,您可以在您的存盤庫中創建自定義方法,您將在其中加入您的關系。此外,最好立即僅過濾當前的分析。存盤庫可能如下所示:
class RiskRepository extends ServiceEntityRepository
{
...
/**
* @return Risk[]
*/
public function findAllWithCurrentAnalysis(): array
{
return $this->createQueryBuilder('risk')
->addSelect('analysis')
->join('risk.analysis', 'analysis')
->andWhere('analysis.currentVersion = :true')
->setParameter('true', true)
->getQuery()
->getResult()
;
}
...
}
您的控制器操作將如下所示:
public function indexAction()
{
$em = $this->em;
$risks = $em->getRepository('App\Entity\Hazardlog\Risk')->findAllWithCurrentAnalysis();
return $this->render('risk/index.html.twig', array(
'risks' => $risks,
));
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/503891.html
