2017-08-21 140 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个查询检索所有数据。简而言之,除非你明确地告诉它,否则教义不会加入相关实体。