1
0
mirror of synced 2024-12-14 07:06:04 +03:00
doctrine2/manual/docs/en/improving-performance/fetch-only-what-you-need.txt

61 lines
4.1 KiB
Plaintext

Maybe the most important rule is to only fetch the data you actually need. This may sound trivial but laziness or lack of knowledge about the possibilities that are available often lead to a lot of unnecessary overhead.
Take a look at this example:
<code type="php">
$record = $table->find($id);
</code>
How often do you find yourself writing code like that? It's convenient but it's very often not what you need. The example above will pull all columns of the record out of the database and populate the newly created object with that data. This not only means unnecessary network traffic but also means that Doctrine has to populate data into objects that is never used. I'm pretty sure you all know why
<code>
SELECT * FROM ...
</code> is bad in any application and this is also true when using Doctine. In fact it's even worse when using Doctrine because populating objects with data that is not needed is a waste of time.
Another important rule that belongs in this category is: **Only fetch objects when you really need them**. Until recently this statement would make no sense at all but one of the recent additions to Doctrine is the ability to fetch "array graphs" instead of object graphs. At first glance this may sound strange because why use an object-relational mapper in the first place then? Take a second to think about it. PHP is by nature a prodecural language that has been enhanced with a lot of features for decent OOP. Arrays are still the most efficient data structures you can use in PHP. Objects have the most value when they're used to accomplish complex business logic. It's a waste of resources when data gets wrapped in costly object structures when you have no benefit of that. Take a look at the following pseudo-code that fetches all comments with some related data for an article, passing them to the view for display afterwards:
<code type="php">
$comments = $query->select("c.id, ...")->from("Comment c")
->leftJoin("c.foo f")
->leftJoin("f.bar b")
->where("c.article_id = ?")
->execute(array(1));
$view->comments = $comments;
</code> Can you think of any benefit of having objects in the view instead of arrays? You're not going to execute business logic in the view, are you? One parameter can save you a lot of unnecessary processing:
<code type="php">
... ->execute(array(1), Doctrine::FETCH_ARRAY);
</code> This will return a bunch of nested php arrays. It could look something like this, assuming we fetched some comments:
<code>
array(5) (
[0] => array(
'title' => 'Title1',
'message' => 'Hello there! I like donuts!',
'author' => array(
'first_name' => 'Bart',
'last_name' => 'Simpson'
)
),
[1] => array(
'title' => 'Title2',
'message' => 'Hullo!',
'author' => array(
'first_name' => 'Homer',
'last_name' => 'Simpson'
)
),
...
)
</code> Here 'author' is a related component of a 'comment' and thus results in a sub-array. If you always use the array syntax for accessing data, then the switch to array fetching requires nothing more than adding the additional parameter. The following code works regardless of the fetching style:
<code type="php">
foreach ($comments as $comment) {
echo $comment['title'] . '<br />';
echo $comment['message'] . '<br />';
echo $comment['author']['first_name'] . ' - ' . $comment['author']['last_name'] . '<br />';
}
</code> **Array fetching is the best choice whenever you need data read-only like passing it to the view for display. And from my experience, most of the time when you fetch a large amount of data it's only for display purposes. And these are exactly the cases where you get the best performance payoff when fetching arrays instead of objects.**
Sometimes, you may want the direct output from PDO instead of an object or an array. To do this, set the hydration mode to **Doctrine::HYDRATE_NONE**. Here's an example:
<code type="php">
$total = Doctrine_Query::create()
->select('SUM(d.amount)')
->from('Donation d')
->execute(array(), Doctrine::HYDRATE_NONE);
</code>