Doctrine 在水合过程中添加了额外的查询,导致“正常”一对一和自引用关系出现 n+1 问题

2023-12-03

News使用一对多自引用方法相互关联(一个消息是父级,可以有多个子级)。更何况各有各News与 具有正常(非自引用)一对一关系Event and Gallery。当我运行简单的 DQL 时:

SELECT n FROM App\Entity\News n WHERE n.parent = :id

然后通过水化结果getResults带默认值的方法HYDRATION_OBJECT值集,在内部某处进行额外查询getResults方法。

SELECT t0.* FROM event t0 WHERE t0.news_id = 2 AND ((t0.deleted_at IS NULL));
SELECT t0.* FROM gallery t0 WHERE t0.news_id = 2 AND ((t0.deleted_at IS NULL));
SELECT t0.* FROM event t0 WHERE t0.news_id = 1 AND ((t0.deleted_at IS NULL));
SELECT t0.* FROM gallery t0 WHERE t0.news_id = 1 AND ((t0.deleted_at IS NULL));

Where news_id = 1 and news_id = 2是第一个查询选择的新闻的子项。

News也没有自引用的一对多关系(我在这里忽略了它们),但是水合不会对它们产生额外的查询。仅当存在时才会出现问题parent涉及的关系where陈述。

如何重现

// news Entity
/**
 * @ORM\Entity(repositoryClass="App\Repository\NewsRepository")
 * @ORM\Table(uniqueConstraints={@UniqueConstraint(name="news_slug_deleted", columns={"slug","deleted_at"})})
 */
class News {
    use SoftDeleteableEntity;

    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;
    /**
     * @ORM\Column(type="string", length=255)
     */
    private $title;

    /**
     * @Gedmo\Slug(fields={"title"})
     * @ORM\Column(length=128)
     */
    private $slug;
/**
     * @ORM\OneToOne(targetEntity="App\Entity\Gallery", mappedBy="news", cascade={"persist", "remove"}, orphanRemoval=true)
     *
     * @var Gallery
     */
    private $gallery;

    /**
     * @ORM\OneToOne(targetEntity="App\Entity\Event", mappedBy="news", cascade={"persist", "remove"}, orphanRemoval=true)
     *
     * @var Event
     */
    private $event;
    /**
     * One News has Many News.
     * @ORM\OneToMany(targetEntity="News", mappedBy="parent")
     */
    private $children;

    /**
     * Many News have One News.
     * @ORM\ManyToOne(targetEntity="News", inversedBy="children")
     * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", nullable=true)
     */
    private $parent;
}
/**
 * @ORM\Entity(repositoryClass="App\Repository\EventRepository")
 * @Gedmo\SoftDeleteable()
 */
class Event
{
    use SoftDeleteableEntity;

    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;
    /**
     * @ORM\OneToOne(targetEntity="App\Entity\News", inversedBy="event", cascade={"persist"})
     * @ORM\JoinColumn(nullable=false)
     */
    private $news;

Gallery实体类似于Event所以我在这里忽略了它。

// News controller

public function index(NewsRepository $newsRepository, $slug)
{
        $news = $newsRepository->findOneBy(['slug' => $slug]);
        $newsRepository->getConnectedNews($news->getId());
}
// news repository

class NewsRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, News::class);
    }
    public function getConnectedNews($newsId) {
        $query = $this->createQueryBuilder('n')->andWhere('n.parent = :id')->setParameter('id', $newsId);
        return $query->getQuery()->getResult(AbstractQuery::HYDRATE_OBJECT);
    }
}

水合作用news有 20 个子级,最终得到: 20 * 2 + 1 (n*r+1) 个查询,其中:

  • (n) 20 是孩子的数量
  • (r) 2 是一对一关系的数量
  • 1 是基本查询

我想防止 Doctrine 对一对一关系进行额外的查询。是教义错误还是不需要的行为或者我在某个地方犯了错误?

总而言之,我只想获取所有没有一对一关系的自引用子项,因为我没有要求检索它们,因此它应该仅使用一个查询来获取所有子项news无需对每个检索到的“新闻”对象进行额外的查询,并且每个对象都是一对一的关系。


该实体中有几个反向的 OneToOne 关系。

反向 OneToOne 关系无法通过 Doctrine 延迟加载,并且很容易成为性能问题。

If you really需要将这些关系映射到inverse一方(不仅是拥有方)确保显式地进行适当的连接,或将这些关联标记为FETCH=EAGER这样 Doctrine 就会为您进行连接。

例如。可以避免可怕的“n+1”问题的查询是:

SELECT n, g, e
    FROM App\Entity\News n
    LEFT JOIN n.gallery g
    LEFT JOIN n.event e
WHERE n.parent = :id

您可以在 Doctrine 中阅读有关 N+1 问题的更多信息here or here.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Doctrine 在水合过程中添加了额外的查询,导致“正常”一对一和自引用关系出现 n+1 问题 的相关文章

  • HTML 表单 POST 到 PHP 页面 [关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 好的 我创
  • 计算两个数字之间的差异

    我想计算两个给定数字之间的差异 例如 1 5 或 24 35 我必须将数组中的数字分开并写出它们之间的差异 如下所示 1 2 3 4 5 或 24 25 26 27 28 29 30 31 32 33 34 35 是否有任何 php 函数可
  • 如何在Web服务中传递URL

    我想将此 URL 作为网址中的值传递http localhost h2orn php verify php email emails hash hash但是 我只能在 符号之前传递 我想传递所有 URL 我正在使用java网络服务 代码在这
  • 这些加密算法有什么区别?

    两者有什么区别MCRYPT RIJNDAEL 128 MCRYPT RIJNDAEL 256 MCRYPT BLOWFISH等等 哪一种最适合网络数据传输 Rijandel 是 AES 的另一个名称 AES 是当前的 一个好的标准 算法 数
  • PSR-4 代码库中条令生成器的解决方法

    在 Windows 机器上使用 Symfony 2 和 Doctrine 我正在尝试 从现有模式生成实体 php app console doctrine mapping import force CoreBundle annotation
  • 如何将 ctype_alpha 与 UTF-8 结合使用

    如何将 ctype alpha 与 UTF 8 一起使用 我有这个代码 if empty POST false if isset POST first name empty POST first name if ctype alpha PO
  • jQuery和PHP中如何知道返回数据是Json还是String?

    我想在客户端 jQuery 检查 PHP 函数返回的数据是否是 Json 对象或 String 来分配不同的函数 如果 json 的格式不正确 jQuery 的 parseJson 将生成异常 您可以将调用包装在 try catch 块中
  • 使用 php 将 HLS Segment (ts) 视频转换并加入到 mp4

    你好我正在使用这个工具 https github com Ejz HLSDownloader https github com Ejz HLSDownloader将 HLS 视频片段从 m3u8 播放列表下载到 ts 文件中 不 我不知道如
  • CSV 从 UTF8 到 ISO-8859-1

    我正在尝试修改我的 CSV 导出 但它不会将我的 CSV 从 UTF 8 转换 保存为 ISO 8859 1 请问我做错了什么吗 实际上自从修改了这个之后 我得到了一个空的 CSV 文件 php 7 0 x function my Gene
  • URL 重写帮助

    RewriteEngine on RewriteCond REQUEST URI index php RewriteRule index php q 1 L 这应该将任何 url 重写为 index php q url 并且它可以工作 反正
  • 如何在 joomla 模块中通过 javascript 发送输入文件类型

    我想将带有 javascript 的文件发送到 php 文件 我的 php 文件中有这个表单
  • 疯狂的 crond 行为。不断使 bash 进程失效

    我有一个看起来像这样的 crontab SHELL bin bash PATH sbin bin usr sbin usr bin MAILTO root HOME 0 59 var www html private fivemin zda
  • 将秒转换为天、小时、分钟和秒

    我想转换一个变量 uptime这是秒 分为天 小时 分钟和秒 Example uptime 1640467 结果应该是 18 days 23 hours 41 minutes 这可以通过以下方式实现DateTime http php net
  • 在 MySQL 中搜索多个单词

    我使用 HTML 表单来允许用户查找数据库表中的条目
  • 如何覆盖 phpunit 中导出的变量?

    我知道我可以设置环境变量 https phpunit de manual current en appendixes configuration html在我的 phpunit xml 里面
  • 使用 php 和 symfony 从数组创建 Excel 文件

    我正在尝试使用 PHP 和 symfony 将数组导出为 XLS 文件 如下面的代码所示 创建 XLS 文件后 我只能获取数组的最后一行 并且它显示在文件的第一行中 似乎 lignes 变量没有增加 我不明白出了什么问题 有人可以帮忙吗 f
  • 需要使用 php 从远程服务器下载与 $_FILES 相同的内容[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 好的 我有处理图像上传的 php 代
  • NodeJS 和 PHP (Laravel) 集成用于 Socket.IO 实时聊天

    目前我有一个我写过的网站PHP通过Laravel 框架 我已经使用写了一个实时聊天nodeJS with 套接字IO and Express现在我想做的是将它集成到我已经编写的 Laravel 网站中 问题是聊天必须在主页中 当前由 Lar
  • PHP - 查找和比较日期

    你好 我有 foreach 我可以在其中获取数据库中的事件数据 我使用数据库中的日期名称 例如 event date 我需要在一个 div 中比较具有相同日期和输出的操作 例如我有这个事件 活动一 9 月 13 日 活动二 9 月 1 日
  • Laravel 5 注销特定用户

    在我的 laravel 5 应用程序中 有一个功能允许具有管理员角色的用户重置非管理员的任何人的密码 但这不会强制该人注销并再次登录 更改密码后如何强制用户注销 我没有对用于验证用户身份或任何内容的中间件进行任何更改 我不知道它是否有效 但

随机推荐