Symfony2 doctrine2与收藏品合作 - 表演

时间:2014-01-25 17:03:44

标签: performance symfony memory collections doctrine-orm

这个问题的关键在于弄清楚哪种技术更好,并听取了一些熟练的symfony2程序员的不同意见。

一个例子将说明挑战和“挑战评级”表,许多人可以对某些挑战进行评级。 (类似于stackoverflow投票问题系统)。

表格如下所示:(like_dislike是boolean(1 = like,0 = dislike)

Challenges table challenge rating table

数据量将为10-200 +挑战率。


使用馆藏

挑战实体

/**
 * Challanges
 *
 * @ORM\Table(name="challanges")
 * @ORM\Entity(repositoryClass="TB\ChallangesBundle\Entity\ChallangesRepository")
 */
class Challanges
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
     * @Assert\NotBlank()
     */
    private $name;

    /**
     * @var string
     *
     * @ORM\Column(name="slug", type="string", length=255, unique=true)
     */
    private $slug;

    /**
     * @var string
     *
     * @ORM\Column(name="description", type="text")
     * @Assert\NotBlank()
     */
    private $description;

    /**
     * @var \DateTime
     * @ORM\Column(name="start_date", type="datetime", nullable=false)
     * @Assert\DateTime()
     */
    private $start_date;

    /**
     * @var \DateTime
     * @ORM\Column(name="end_date", type="datetime", nullable=false)
     * @Assert\DateTime()
     */
    private $end_date;

    /**
     * @ORM\ManyToOne(targetEntity="TB\UserBundle\Entity\User", fetch="EXTRA_LAZY")
     * @ORM\JoinColumn(name="owner_id", referencedColumnName="id", nullable=false)
     */
    protected $owner;

    /**
     * @ORM\OneToMany(targetEntity="TB\ChallangesBundle\Entity\ChallangeRating", mappedBy="challange", cascade={"persist", "remove"})
     */
    protected $likes;

/**
 * Constructor
 */
public function __construct()
{
    $this->likes = new \Doctrine\Common\Collections\ArrayCollection();
}


/**
 * Add likes
 *
 * @param \TB\ChallangesBundle\Entity\ChallangeRating $likes
 * @return Challanges
 */
public function addLike(\TB\ChallangesBundle\Entity\ChallangeRating $likes)
{
    $this->likes[] = $likes;

    return $this;
}

/**
 * Remove likes
 *
 * @param \TB\ChallangesBundle\Entity\ChallangeRating $likes
 */
public function removeLike(\TB\ChallangesBundle\Entity\ChallangeRating $likes)
{
    $this->likes->removeElement($likes);
}

/**
 * Get likes
 *
 * @return \Doctrine\Common\Collections\Collection 
 */
public function getLikes()
{
    return $this->likes;
}

public function filterLikesInChallenge($like_dislike) {
    $criteria = Criteria::create();
    $criteria->where(Criteria::expr()->eq('like_dislike', $like_dislike));

    return $this->likes->matching($criteria);
}

public function checkIfUserRatedAlready(\TB\UserBundle\Entity\User $user)
{
    $criteria = Criteria::create();
    $criteria->where(Criteria::expr()->eq('fan', $user));

    return $this->likes->matching($criteria);
}

挑战评级实体

<?php

namespace TB\ChallangesBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * ChallangeRating
 *
 * @ORM\Table(name="challange_rating")
 * @ORM\Entity(repositoryClass="TB\ChallangesBundle\Entity\ChallangeRatingRepository")
 */
class ChallangeRating
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var boolean
     *
     * @ORM\Column(name="like_dislike", type="boolean")
     */
    private $like_dislike;

    /**
     * @ORM\ManyToOne(targetEntity="TB\UserBundle\Entity\User", inversedBy="fans")
     */
    protected $fan;

    /**
     * @ORM\ManyToOne(targetEntity="TB\ChallangesBundle\Entity\Challanges", inversedBy="likes")
     */
    protected $challange;


    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Get like_dislike
     *
     * @return boolean 
     */
    public function getLikeDislike()
    {
        return $this->like_dislike;
    }

    /**
     * Set like_dislike
     *
     * @param boolean $like_dislike
     * @return ChallangeRating
     */
    public function setLikeDislike($like_dislike)
    {
        $this->like_dislike = $like_dislike;

        return $this;
    }

    /**
     * Set fan
     *
     * @param \TB\UserBundle\Entity\User $fan
     * @return ChallangeRating
     */
    public function setFan(\TB\UserBundle\Entity\User $fan = null)
    {
        $this->fan = $fan;

        return $this;
    }

    /**
     * Get fan
     *
     * @return \TB\UserBundle\Entity\User 
     */
    public function getFan()
    {
        return $this->fan;
    }

    /**
     * Set challange
     *
     * @param \TB\ChallangesBundle\Entity\Challanges $challange
     * @return ChallangeRating
     */
    public function setChallange(\TB\ChallangesBundle\Entity\Challanges $challange = null)
    {
        $this->challange = $challange;

        return $this;
    }

    /**
     * Get challange
     *
     * @return \TB\ChallangesBundle\Entity\Challanges 
     */
    public function getChallange()
    {
        return $this->challange;
    }
}

好的,现在我想:

  1. 显示挑战详情
  2. 显示率特征(喜欢,不喜欢)以及喜欢和不喜欢的数量
  3. 显示已对此质询进行评分的所有用户的列表
  4. 控制器

    获得$ challenge的经典开始

    // this will take care of point number 1 (display challenge details) (1.)
    $challange = $challangesRepo->findOneBy(array('slug'=>$slug)); 
    
    // display numbers of likes and dislikes for certain challenge (2.)
    

    但现在是一个决定......

    问题1

    我应该通过从querybuilder查询数据库获得喜欢的吗? (经典选择计数)

    我应该使用这样的集合和标准吗? :

        $challangeLikes = $challange->filterLikesInChallenge(1);
        $challangeDislikes = $challange->filterLikesInChallenge(0);
    

    **内存使用效果更好? DB表现更好的是什么? **

    如果我没有错,则以下两个方法执行以下两个查询:

    SELECT 
      t0.id AS id1, 
      t0.like_dislike AS like_dislike2, 
      t0.fan_id AS fan_id3, 
      t0.challange_id AS challange_id4 
    FROM 
      challange_rating t0 
    WHERE 
      (
        t0.like_dislike = ? AND t0.challange_id = ? 
      )
    Parameters: [1, 12] 
    
    SELECT 
      t0.id AS id1, 
      t0.like_dislike AS like_dislike2, 
      t0.fan_id AS fan_id3, 
      t0.challange_id AS challange_id4 
    FROM 
      challange_rating t0 
    WHERE 
      (
        t0.like_dislike = ? AND t0.challange_id = ? 
      )
    

    现在我可以将喜欢,不喜欢的数量传递给以下视图:

    'challangeLikes'=>$challangeLikes->count(),
    'challangeDislikes'=>$challangeDislikes->count(),
    

    问题2

    如果我想知道某位用户是否已经对此挑战进行了评分,该怎么办?

    再次......

    *我应该使用经典的querybuilder样式和select count *

    我应该使用像这样的方法:

    $ratedAlreadyCol = $challange->checkIfUserRatedAlready($user)->first();
    

    那会实际执行另一个查询吗?像经典选择计数的东西,但该集合将为我做这个?所以这不是在一些大型内存阵列中搜索allll喜欢但是它是对DB的查询?

    SELECT 
      t0.id AS id1, 
      t0.like_dislike AS like_dislike2, 
      t0.fan_id AS fan_id3, 
      t0.challange_id AS challange_id4 
    FROM 
      challange_rating t0 
    WHERE 
      (
        t0.fan_id = ? AND t0.challange_id = ? 
      )
    Parameters: [25, 12] 
    

    问题3 - 可能是表演最重要的

    我想展示所有“粉丝 - 评定某项挑战的人”......

    ...再次

    我应该在存储库中创建一个单独的querybuilder方法,选择针对某些挑战的所有评级,并使用内部联接到users表(这样我可以显示个人资料图像和用户名)

    我是否应该获得所有评级,并在其中通过它来完成:

     $challangeLikesCollection = $challange->getLikes();
    
    {% for bla bla
    

    BUT

    如果我这样做的话......教义会对循环中的每个“粉丝”执行一个针对用户表的选择查询...当有人说... 200粉丝......那不是好吧?

    奖金问题

    能以某种方式请他提供处理这些情况的方法吗?有什么建议?

    或者您使用其他任何技术?

    我非常关心内存使用和数据库加载时间,因为它将在任何地方使用,每个用户都会有这样一个列出不同挑战的列表。该列表将包括让我们说15个挑战,并将所有喜欢,不喜欢的内容连接到列表中的每个挑战等等......表演......

    感谢您的解释,提示和提示,以帮助我和其他读者在另一个层面上移动!

1 个答案:

答案 0 :(得分:0)

我会做以下事情:

  1. 稍微规范化并将number of likesnumber of dislikes字段添加到Challenge,并在addLikeremoveLike

    <中更新这些值/ LI>
  2. like_dislike重命名为like,因为它是布尔字段,1表示0表示不喜欢

  3. 使用单独的查询查询用户列表并使用数组水化和INDEXBY用户名(它必须是唯一的或用户ID)或者可以创建自定义水分器

    SELECT u.username,u.photo FROM User u INNER JOIN u.ratings WITH r.fan =:fan INDEX BY u.username

    或类似的东西。您可以检查当前用户的用户名是否在阵列中。

  4. 我认为这可能足够高效。

    一些解释:

    INDEX BY means结果集合或数组键(索引)将是字段的值(此字段必须是唯一的)。当您使用INDEX BY时,结果集将包含已知的键,因此您可以直接在恒定时间内(并且不必搜索整个结果集)到达(例如检查是否存在)单个结果。

    Doctrine在下面使用PDO,水化意味着如何处理PDO结果集并将其转换为其他内容。默认对象水合意味着结果集将被转换为对象图,这是一个非常昂贵的操作。有other hydration modes便宜,但你松散了一些灵活性。例如。如果你使用数组水合,结果将是一个数组数组,所以你不能修改它(我的意思是坚持回数据库)所以它只是为了阅读而结果不是实体对象你不能使用它的方法,例如定制的吸气剂。如果需要,您可以创建custom hydrators

相关问题