lion

A tumble-style blog that has bringing you nonsense since 2006
Jun 26
1 year, 2 months ago.

Doctrine, hydrate_record, & lazy loading

So, through my adventures with Doctrine I’ve encountered quite a few bugs that a normal (or power) user would come across. The problem I am going to mention today is one that can severely hurt a site’s loading time and cause query backup to the database.

It begins with code like this:

  $q = Doctrine_Query::create()->
           from("profile p")->
           select("p.name, p.zipcode")->
           whereIn("p.id", array(1,2,3,4,5))->
           execute(array(), Doctrine::HYDRATE_RECORD);

Simple code, pull the list of names and zip codes from the database where the ID’s coincide with the given array.

<?php foreach($q AS $person): ?>
  <?php echo $person->name ?> - <?php echo $person->zipcode ?>
  <br />
<?php endforeach; ?>

The result would be something such as

Bob - 63122
Tom - 63122
Frank - 63025
Jim - 63123
Bill - 61236

Now here is the problem: Let’s assume that Jim doesn’t have his zip code in the database. Instead of “62123″ the result of “$person->zipcode” would be null.

Bob - 63122
Tom - 63122
Frank - 63025
Jim -
Bill - 61236

Unfortunately, the null response kicks Doctrine’s lazy field loading feature into drive. Lazy field loading is Doctrines ability to load data from the database not specified in a select() tag. Read more about it here. So, in short, the null response tricks Doctrine into thinking that the field wasn’t populated by the hydrator, then creates a query to grab the entire row.
Now, imagine that being looped five times if none of the users above had the zip codes filled in. That’s one query for each person. Imagine it being scaled higher? We have a potential problem here.

There are two solutions. Theeasy way and then modifying Doctrine itself.

The first solution is to use HYDRATE_ARRAY or HYDRATE_SCALAR. These methods can not perform lazy field loading due to the fact that the hydrator binds the results to an array which is not double checked when outputted (such as the case for objects).

The next solution (and the method I chose) was to modify Doctrine’s coding itself, as there were cases in which objects were necessary. I basically choose to turn lazy-loading off by default, and then added a switch to enable and disable the feature in the core code of Doctrine. The affected files were: /Doctrine.php, doctrine/Configurable.php, and doctrine/Record.php.
Like I said, by default lazy loading is turned off, so if you need it (such as in the case of a plugin), you can turn it on with:

  //on
  Doctrine_Manager::getInstance()->
    setAttribute('lazy_field_loading', true);

  //off
  Doctrine_Manager::getInstance()->
    setAttribute('lazy_field_loading', false);

The modified files are here:
Doctrine Lazy Loading 1.1.2

That’s pretty much a wrap for that. If anyone wants specifics on what I changed, feel free to ask.


Chatter



Add your own comment

Formatting Help


* required | * will be hidden

Dan is

& this is his thumblish-blog.
I want to know more!

btw, you can contact me at:
dan[at]contagious.nu

Elsewhere