Are Doctrine relations affecting application perfo

2020-04-01 08:28发布

问题:

I am working on a Symfony project with a new team, and they decide to stop using Doctrine relations the most they can because of performances issues.

For instance I have to stock the id of my "relation" instead of using a ManyToOne relation.

But I am wondering if it is a real problem?

The thing is, it changes the way of coding to retrieve information and so on.

回答1:

The performance issue most likely comes from the fact that queries are not optimised.

If you let Doctrine (Symfony component that handle the queries) do the queries itself (by using findBy(), findAll(), findOneBy(), etc), it will first fetch what you asked, then do more query as it will require data from other tables.

Lets take the most common example, a library.

Entities

  • Book
  • Author
  • Shelf

Relations

  • One Book have one Author, but one Author can have many Books (Book <= ManyToOne => Author)
  • One Book is stored in one Shelf (Book <= OneToOne => Sheilf)

Now if you query a Book, Doctrine will also fetch Shelf as it's a OneToOne relation.
But it won't fetch Author. In you object, you will only have access to book.author.id as this information is in the Book itself.

Thus, if in your Twig view, you do something like {{ book.author.name }}, as the information wasn't fetched in the initial query, Doctrine will add an extra query to fetch data about the author of the book.

Thus, to prevent this, you have to customize your query so it get the required data in one go, like this:

public function getBookFullData(Book $book) {
    $qb=$this->createQueryBuilder('book');

    $qb->addSelect('shelf')
       ->addSelect('author')
       ->join('book.shelf', 'shelf')
       ->join('book.author', 'author');

    return $qb->getQuery()->getResult();
}

With this custom query, you can get all the data of one book in one go, thus, Doctrine won't have to do an extra query.

So, while the example is rather simple, I'm sure you can understand that in big projects, letting free rein to Doctrine will just increase the number of extra query.
One of my project, before optimisation, reached 1500 queries per page loading...

On the other hand, it's not good to ignore relations in a database. In fact, a database is faster with foreign keys and indexes than without.

If you want your app to be as fast as possible, you have to use relations to optimise your database query speed, and optimise Doctrine queries to avoid a foul number of extra queries.

Last, I will say that order matter. Using ORDER BY to fetch parent before child will also greatly reduce the number of query Doctrine might do on it's own.

[SIDE NOTE]

You can also change the fetch method on your entity annotation to "optimise" Doctrine pre-made queries.

  • fetch="EXTRA_LAZY
  • fetch="LAZY
  • fetch="EAGER

But it's not smart, and often don't really provide what we really need.
Thus, custom queries is the best choice.