博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Mastering Symfony2 Performance – Doctrine
阅读量:6172 次
发布时间:2019-06-21

本文共 4631 字,大约阅读时间需要 15 分钟。

  hot3.png

Doctrine ORM is a powerful tool which can facilitate an access to the database layer providing mapping the source data to objects. Unfortunately, as every next abstraction layer, such possibilities come with a performance overhead.

Based on some common use-cases, the article will cover topics related with improving the performance when using Doctrine ORM. We’ve choosen it as it comes in a Symfony Standard distribution and is integrated out-of-box within your project — it’s the most commonly ORM used in .

0. Always control your Symfony2 Profiler toolbar

The first, key rule of developing efficient Symfony2 project is to always control what is going on in the profiler’s toolbar.

Thanks to it, you can always spot weak points of your application – rise of the number of queries can show you that something may be inefficient, some queries may leak.

In the Symfony Profiler you can also get into details of the database queries:

  • Click on the blue (+) to get a nicely formatted query

  • Time – shows the time of the statement execution

  • Explain query – shows an of the query

Btw. click on the profiler below to get the queries explained :-)

1. Avoid Object Hydration when handling many entities

The process of Hydration is one of the most time and memory consuming in the ORM.

When you’re retrieving many rows from the database only to show them in the view (e.g. in a some sort of listing/CRUD), hydrating them to the object may not make sense.

Instead you should use simpler hydration modes like arrays/scalar:

getQuery()->getArrayResult();$scalarResults = $qb->getQuery()->getScalarResult();

2. Don’t load the whole entity if you only need reference to it

Sometimes you’re in the situation when having an Entity and an ID of the other one which you will like to associate. In that case making an extra find($id) operation — SELECT — can lead to an unnecessary additional database statement.

Thanks to the Doctrine’s Reference Proxies you don’t have to retrieve the whole entity from the database only to associate it with another one.

You can use its ID instead:

addFriend($em->getReference('Octivi\Entity\User', $friendId));$em->persist($user);$em->flush();

3. Update multiple database rows using Update statement

When you have to update multiple entities, retrieving them all from the database and iterating over ORM entities is known as a bad practice.

You should never do like:

getReference('Octivi\Entity\User', $friendId);$users = $this->findAll();foreach ($users as $user) {    $user->setFriend($friend);    $em->persist($user);}$em->flush();

Instead, you should rely on the UPDATE query:

update('Octivi:User', 'u')    ->set('u.friend', $friendId)    ->getQuery()->execute();

Thanks to it, we only execute one SQL UPDATE statement instead of N-updates for each User entity.

4. Use the advantages of Lazy Collections

From the 2.1 version, Doctrine added support for lazy collections.

With extra lazy collections you can now not only add entities to large collections but also paginate them easily using a combination of count and slice.

Having ManyToMany or OneToMany mappings defined with fetch type of EXTRA_LAZY:

/** * @Entity */class CmsGroup{    /**     * @ManyToMany(targetEntity="CmsUser", mappedBy="groups", fetch="EXTRA_LAZY")     */    public $users;}

makes, that calling Collection’s methods like:

  • $users->count();

  • $users->slice(…)

won’t load the whole collection from the database to the memory.

Instead, Doctrine will cleverly execute appropriate queries such as COUNT.

5. Beware of loading entities in a loop

By default, Doctrine won’t make JOIN for associated entities. The common situation is when you have entities with N-1 association (e.g. one article can have only one author) and you want to display a list of articles with their author’s names.

Take a look at the sample code:

In some controller you are finding all/some articles:

getEntityManager();$articlesRepo = $em->getRepository('OctiviTestBundle:Article');$articles = $articlesRepo->findAll();

In the view you want to display the name of the article’s author:

{% for article in articles %}    {
{ article.author.name }}    {
{ article.content }}{% endfor %}

Such code will lead to additional SELECT statements for every article’s author.

Instead, you should use JOIN in your DQL/Query Builder:

createQueryBuilder('qb1');$qb->add('select', 'a, au')        ->add('from', 'OctiviTestBundle:Article a')        ->join('a.author', 'au');

which will get articles with their authors in one SELECT query. So next calls for article.getAuthor() won’t make any extra database queries.

转载于:https://my.oschina.net/imot/blog/297455

你可能感兴趣的文章
系统进程管理工具Process Explorer
查看>>
富士通仍执着SPARC架构芯片 将坚持推新
查看>>
易宪容:企业要利用大数据挖掘潜在需求
查看>>
微软声称Win10周年更新为Edge浏览器带来更好电池寿命
查看>>
混合云是企业IT的未来吗?
查看>>
LINE在日本取得成功 但全球化之路还很长
查看>>
红帽云套件新增QuickStart Cloud Installer,加快私有云部署
查看>>
MapXtreme 2005 学习心得 一些问题(八)
查看>>
流量精细化运营时代,营销SaaS之使命——流量掘金
查看>>
雅虎同意出售核心资产
查看>>
Win10大丰收的节奏 微软收编iOS全部150万应用
查看>>
智慧城市要除“城市病” 中兴通讯开辟新增长极
查看>>
Opera已确认解散iOS开发团队
查看>>
DevOps:新的业务浪潮
查看>>
CERT:启用EMET的Windows 7比Windows 10更加安全
查看>>
LINE上市:一场迟到、勇敢又无奈的IPO
查看>>
OA选型:OA系统工作流是核心
查看>>
如何发现“利用DNS放大攻击”的服务器
查看>>
《Arduino开发实战指南:LabVIEW卷》——第2章 Arduino软件
查看>>
京津冀大数据走廊起笔谋篇
查看>>