[英]symfony3 inverse entity mapping slow
我得到以下實體:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
/**
* Productnum
*
* @ORM\Table(name="productnum")
* @ORM\Entity
*/
class Productnum
{
/**
* @var object
*
* @ORM\OneToMany(
* targetEntity="AppBundle\Entity\Products",
* mappedBy="productnum",
* cascade={"persist", "remove"}
* )
*/
protected $productnumInverse;
/**
* Constructor
*/
public function __construct()
{
$this->productnumInverse = new ArrayCollection();
}
/**
* Get productnumInverse
*
* @return Collection
*/
public function getProductnumInverse()
{
return $this->productnumInverse;
}
}
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
/**
* Products
*
* @ORM\Table(name="products")
* @ORM\Entity
*/
class Products
{
/**
* @var \AppBundle\Entity\Productnum
*
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Productnum", inversedBy="productnumInverse")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="productnum_id", referencedColumnName="row_id")
* })
*/
public $productnum;
/**
* @var object
*
* @ORM\OneToMany(
* targetEntity="AppBundle\Entity\Product_region", fetch="EAGER",
* mappedBy="productid",
* cascade={"persist", "remove"}
* )
*/
protected $productInverse;
/**
* Constructor
*/
public function __construct()
{
$this->productInverse = new ArrayCollection();
}
}
<?php
namespace AppBundle\Entity;
use AppBundle\AppBundle;
use AppBundle\Entity\Productnum_filial;
use Doctrine\ORM\Mapping as ORM;
/**
* Productnum_region
*
* @ORM\Table(name="productnum_region")
* @ORM\Entity
*/
class Productnum_region
{
//regular getters and setters here...
}
和一個映射實體:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Product_region
*
* @ORM\Table(name="product_region")
* @ORM\Entity
*/
class Product_region
{
/**
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var \AppBundle\Entity\Products
*
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Products")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="product_id", referencedColumnName="row_id")
* })
*
*/
private $productid;
/**
* @var \AppBundle\Entity\Productnum_region
*
* @ORM\ManyToOne(targetEntity="AppBundle\Entity\Productnum_region")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="region_id", referencedColumnName="id")
* })
*/
private $regionid;
}
在我的控制器中,我得到了以下代碼
$sql = sprintf("SELECT p FROM 'AppBundle:Productnum' p");
$productnums = $em->createQuery($sql)
->setFirstResult($start)
->setMaxResults($length)
->getResult();
$data = [];
foreach($productnums as $productnum) {
$prods = '';
foreach($productnum->getProductnumInverse() as $product) {
$filials = [];
$regions = [];
if($product && $product->getAllregions()){
$regions[] = $filials[] = 'All';
} elseif($product && $product->getAllfilials()){
$filials[] = 'All';
$regs = $product->getProductInverse();
foreach($regs as $reg){
$regions[] = $reg->getRegionid()->getName();
}
}elseif($product){
$regs = $product->getProductInverse();
foreach($regs as $reg){
$fil = $reg->getRegionid()->getFilial()->getName();
if(!in_array($fil, $filials)){
$filials[] = $fil;
}
$regions[] = $reg->getRegionid()->getName();
}
}
}
問題是,在我的本地計算機上,此代碼可以正常工作,但是在遠程服務器上,它的運行速度非常慢。 我在本地計算機和服務器上都打開了Symfony探查器,發現在本地計算機上(可以),完成了336 DB(總共1.5秒)的查詢,完成了大部分查詢,如下所示:
SELECT t0.id AS id_1, t0.name AS name_2, t0.code AS code_3, t0.filial_id AS filial_id_4 FROM productnum_region t0 WHERE t0.id = ?
Parameters: [0 => 100]
和
SELECT t0.row_id AS row_id_1, ... t0.productnum_id AS productnum_id_21, t22.id AS id_23, t22.product_id AS product_id_24, t22.region_id AS region_id_25 FROM products t0 LEFT JOIN product_region t22 ON t22.product_id = t0.row_id WHERE t0.productnum_id = ?
Parameters: [0 => 945]
而在我的服務器上,總共有36個查詢(總共20秒,BAD),其中一個查詢(可能是最慢的查詢)如下:
SELECT t0.row_id AS row_id_1, ... t0.productnum_id AS productnum_id_21, t22.id AS id_23, t22.product_id AS product_id_24, t22.region_id AS region_id_25
FROM products t0 LEFT JOIN product_region t22 ON t22.product_id = t0.row_id WHERE t0.row_id IN (?)
Parameters: [ 0 => [ 0 => 2, 1 => 97, 2 => 212, 3 => 225, 4 => 297, 5 => 355, 6 => 356, 7 => 482, 8 => 571, 9 => 737, 10 => 789
...MANY MANY MANY data here...
因此,問題在於,如何在不同的計算機上將相同的代碼轉換為不同的查詢,以及如何避免這種情況?
謝謝
看起來您在數據庫設計或代碼上可能犯了一個整體錯誤,這要求您有4個foreach
循環和2個if
語句都嵌套在一起。
要專門回答您的問題-您需要在查詢中加入相應的實體-Doctrine不會為您這樣做。 因此,當您執行此操作時:
foreach($productnum->getProductnumInverse() as $product) {
通過該循環的每次迭代,Doctrine都會單獨查詢該$product
,因為它沒有在原始查詢中選擇它。 這就是為什么您只需要查看336個數據庫查詢的原因。 代替:
SELECT p FROM 'AppBundle:Productnum' p
您的查詢應如下所示:
SELECT p, pi, pip, pir
FROM AppBundle:Productnum p
JOIN p.productnumInverse pi
JOIN pi.product pip
JOIN pi.region pir
這將大大減少您正在運行的查詢的數量-理想情況下,您應該減少到1個查詢來檢索所有這些數據。 簡而言之,除非您特別告知,Doctrine不會加入關聯的實體。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.