AR populateRecord is slow

AR in Yii is very efficient but it’s slower than using DAO approach. One of Russian community members profiled both his DAO implementation and AR implementation and found that bottlenech here is not SQL generated but record population at CActiveRecord::populateRecord(). Noticeable from about 30 records.




public function populateRecord($attributes,$callAfterFind=true)

{

    if($attributes!==false)

    {

        $record=$this->instantiate($attributes);

        $record->setScenario('update');

        $md=$record->getMetaData();

        foreach($attributes as $name=>$value)

        {

            if(property_exists($record,$name)) // this check is SLOW

                $record->$name=$value;         

            else if(isset($md->columns[$name]))

                $record->_attributes[$name]=$value;

        }

        $record->_pk=$record->getPrimaryKey();

        $record->attachBehaviors($record->behaviors());

        if($callAfterFind)

            $record->afterFind();

        return $record;

    }

    else

        return null;

}

Really? property_exists() is expected to be a fast call. Could you please show the relevant profiling results? Thanks.

1000 records, default populateRecord: ~1000ms.

1000 records, populateRecord just without property_exists(): ~525ms.

1000 records, populateRecord without filling $record->_attributes, metadata, behaviours, etc. Only filling properties without property_exists(): ~250ms.

I just did a small test. Calling property_exists of an AR object 1000 times takes 0.8ms.




$a=new User;

$start=microtime(true);

for($i=0;$i<1000;++$i)

{

    if(property_exists($a,'username'))

        $b=1;

    else

        $b=2;

}

$end=microtime(true);

echo 'total '.($end-$start);



Something wrong. I just did a small test too:

Select 1000 records with default populateRecord() take average 191ms

Now let’s comment property_exist()




...

foreach($attributes as $name=>$value)

{

	/*if(property_exists($record,$name))

		$record->$name=$value;

	else*/ if(isset($md->columns[$name]))

		$record->_attributes[$name]=$value;

}

...



And now selecting 1000 records with modified populateRecord() take average 187ms

Hw config: Phenom X3 710, 4Gb RAM, 10000rpm WD Raptor, Win7, xampp 1.7.2 with standart config