SQL query opmitization for HABTM in CakePHP

My last SQL optimization post found no response from the CakePHP community; which makes me wonder how many are actually using ACL with large databases. Anyhow, the ticket was submitted and gwoo seemed to approve the results. I can also now confirm that the last suggested indexes will give another push to your performance:

ARO: alias ACO: model and foreign_key

Now what’s that about HABTM? While reading the source code for the Model class, I stumbled on the Model::_deleteLinks() method:

function _deleteLinks($id) {
   $db =& ConnectionManager::getDataSource($this->useDbConfig);
   foreach ($this->hasAndBelongsToMany as $assoc => $data) {
      if (isset($data['with'])) {
         $model =& $this->{$data['with']};
         $records = $model->findAll(array($data['foreignKey'] => $id), $model->primaryKey, null, null, null, -1);

     if (!empty($records)) {
        foreach ($records as $record) {
           $model->delete($record[$model->name][$model->primaryKey]);
        }
     }
  } else {
     $table = $db->name($db->fullTableName($data['joinTable']));
     $conditions = $db->name($data['foreignKey']) . ' = ' . $db->value($id);
     $db->query("DELETE FROM {$table} WHERE {$conditions}");
  }

} }

If you look carefully, you will notice a useless loop in the case your HABTM has the ‘with’ key set. That means that for every association record there is for the foreignKey, an SQL query will be committed - some food for thought…

I came up with a quick alternative that still hasn’t been really tested but it should work:

function _deleteLinks($id) {
   $db =& ConnectionManager::getDataSource($this->useDbConfig);
   foreach ($this->hasAndBelongsToMany as $assoc => $data) {
      if (isset($data['with'])) {
         $model =& $this->{$data['with']};
         $table = $model->useTable;
         $conditions = $db->name($data['foreignKey']) . ' = ' . $id;
     } else {
         $table = $db->name($db->fullTableName($data['joinTable']));
         $conditions = $db->name($data['foreignKey']) . ' = ' . $db->value($id);
      }
      $db->query("DELETE FROM {$table} WHERE {$conditions}");
   }
}
I also asked gwoo again before making a fool of myself and he suggested it be submitted as an enhancement.

That’s it for now, thought I’d share that - I believe you’d want to make the changes until they are implemented in the core (if you care about performance that is).

2 Responses to “SQL query opmitization for HABTM in CakePHP”

  1. AD7six Says:

    Hi,

    It’s good to see tweaks being suggested (as tickets); if they have diffs/patches and a test case they are likely to get looked at a lot quicker than without.

    I wonder if the reliance in this method on query could cause problems with not-mySql dbs, it’s quite a simple query so maybe not but …. test cases allow such ponderings to be answered quite quickly :)

    keep up the (myway? Ok a diff with a side of test-case please) patchin’,

    cheers,

    AD

  2. Jad Says:

    AD7Six: You’re totally right about the tests. Too much work right now to write one, so I thought I should at least share it - maybe someone else can write the test if he/she is concerned with performance? hint, hint

    TBH, having to be portable across different DB engines slipped my mind at the time of writing; but, with my limited experience I believe it shouldn’t cause any problem. Hopefully I’ll have some kind of test when I’ll be wrapping the app, - until then, too much work to worry about.

    Oh, before I forget, thanks for dropping by; and since I never had the chance to comment on your blog, just wanted to say cheers for all the bits I gathered there.

    Jad

Leave a Reply