2017-08-21 181 views
0

我得到了以下實體:symfony3逆實體映射慢

<?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... 

所以問題是怎麼會發生,不同的機器上的相同的代碼將轉換爲不同的查詢,以及如何可以避免這種情況?

謝謝

+0

你是否開始使用相同環境的應用程序?(prod/dev) – svgrafov

+0

我建議重新構思這個概念,因爲超過300個簡單計算的查詢肯定太多了。 – eRIZ

+0

你好 - 我的回答是否有助於解決你的問題? –

回答

1

它看起來像你可能有你的數據庫設計或代碼,需要你有4個foreach環和2條if語句都嵌套在一起的整體錯誤。

要專門回答您的問題 - 您需要加入您的查詢中的相應實體 - 原則不會爲您做。所以,當你執行此:

foreach($productnum->getProductnumInverse() as $product) { 

通過循環來實現,原則是要單獨查詢該$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個查詢檢索所有數據。簡而言之,除非你明確地告訴它,否則教義不會加入相關實體。