簡體   English   中英

symfony3逆實體映射慢

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM