1
0
mirror of synced 2024-12-13 06:46:03 +03:00

[2.0] Started adding performance regression tests. More object hydration performance improvements.

This commit is contained in:
romanb 2009-05-14 14:57:08 +00:00
parent e79c45f9ac
commit eea4391598
8 changed files with 449 additions and 149 deletions

View File

@ -174,26 +174,26 @@ abstract class AbstractHydrator
foreach ($data as $key => $value) {
// Parse each column name only once. Cache the results.
if ( ! isset($cache[$key])) {
if ($this->_resultSetMapping->isIgnoredColumn($key)) {
if (isset($this->_resultSetMapping->ignoredColumns[$key])) {
$cache[$key] = false;
} else if ($this->_resultSetMapping->isScalarResult($key)) {
} else if (isset($this->_resultSetMapping->scalarMappings[$key])) {
$cache[$key]['fieldName'] = $this->_resultSetMapping->getScalarAlias($key);
$cache[$key]['isScalar'] = true;
} else if ($this->_resultSetMapping->isFieldResult($key)) {
} else if (isset($this->_resultSetMapping->fieldMappings[$key])) {
$classMetadata = $this->_resultSetMapping->getOwningClass($key);
$fieldName = $this->_resultSetMapping->getFieldName($key);
$fieldName = $this->_resultSetMapping->fieldMappings[$key];
$classMetadata = $this->_lookupDeclaringClass($classMetadata, $fieldName);
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['isScalar'] = false;
$cache[$key]['type'] = Type::getType($classMetadata->getTypeOfField($fieldName));
$cache[$key]['isIdentifier'] = $classMetadata->isIdentifier($fieldName);
$cache[$key]['dqlAlias'] = $this->_resultSetMapping->getEntityAlias($key);
$cache[$key]['dqlAlias'] = $this->_resultSetMapping->columnOwnerMap[$key];
} else {
// Discriminator column
$cache[$key]['isDiscriminator'] = true;
$cache[$key]['isScalar'] = false;
$cache[$key]['fieldName'] = $key;
$cache[$key]['dqlAlias'] = $this->_resultSetMapping->getEntityAlias($key);
$cache[$key]['dqlAlias'] = $this->_resultSetMapping->columnOwnerMap[$key];
}
}
@ -245,21 +245,20 @@ abstract class AbstractHydrator
foreach ($data as $key => $value) {
// Parse each column name only once. Cache the results.
if ( ! isset($cache[$key])) {
if ($this->_resultSetMapping->isIgnoredColumn($key)) {
if (isset($this->_resultSetMapping->ignoredColumns[$key])) {
$cache[$key] = false;
continue;
} else if ($this->_resultSetMapping->isScalarResult($key)) {
$cache[$key]['fieldName'] = $this->_resultSetMapping->getScalarAlias($key);
} else if (isset($this->_resultSetMapping->scalarMappings[$key])) {
$cache[$key]['fieldName'] = $this->_resultSetMapping->scalarMappings[$key];
$cache[$key]['isScalar'] = true;
} else {
$classMetadata = $this->_resultSetMapping->getOwningClass($key);
$fieldName = $this->_resultSetMapping->getFieldName($key);
$fieldName = $this->_resultSetMapping->fieldMappings[$key];
$classMetadata = $this->_lookupDeclaringClass($classMetadata, $fieldName);
//$fieldName = $classMetadata->getFieldNameForLowerColumnName($columnName);
$cache[$key]['fieldName'] = $fieldName;
$cache[$key]['isScalar'] = false;
$cache[$key]['type'] = Type::getType($classMetadata->getTypeOfField($fieldName));
$cache[$key]['dqlAlias'] = $this->_resultSetMapping->getEntityAlias($key);
$cache[$key]['dqlAlias'] = $this->_resultSetMapping->columnOwnerMap[$key];
}
}
@ -284,8 +283,8 @@ abstract class AbstractHydrator
*/
protected function _getCustomIndexField($alias)
{
return $this->_resultSetMapping->hasIndexBy($alias) ?
$this->_resultSetMapping->getIndexByField($alias) : null;
return isset($this->_resultSetMapping->indexByMap[$alias]) ?
$this->_resultSetMapping->indexByMap[$alias] : null;
}
/**

View File

@ -88,16 +88,17 @@ class ArrayHydrator extends AbstractHydrator
foreach ($rowData as $dqlAlias => $data) {
$index = false;
if ($this->_resultSetMapping->hasParentAlias($dqlAlias)) {
if (isset($this->_resultSetMapping->parentAliasMap[$dqlAlias])) {
// It's a joined result
$parent = $this->_resultSetMapping->getParentAlias($dqlAlias);
$relation = $this->_resultSetMapping->getRelation($dqlAlias);
$parent = $this->_resultSetMapping->parentAliasMap[$dqlAlias];
$relation = $this->_resultSetMapping->relationMap[$dqlAlias];
$relationAlias = $relation->getSourceFieldName();
$path = $parent . '.' . $dqlAlias;
// Get a reference to the right element in the result tree.
// This element will get the associated element attached.
if ($this->_resultSetMapping->isMixedResult() && isset($this->_rootAliases[$parent])) {
if ($this->_resultSetMapping->isMixed && isset($this->_rootAliases[$parent])) {
$key = key(reset($this->_resultPointers));
// TODO: Exception if $key === null ?
$baseElement =& $this->_resultPointers[$parent][$key];
@ -154,14 +155,14 @@ class ArrayHydrator extends AbstractHydrator
if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
$element = $rowData[$dqlAlias];
if ($field = $this->_getCustomIndexField($dqlAlias)) {
if ($this->_resultSetMapping->isMixedResult()) {
if ($this->_resultSetMapping->isMixed) {
$result[] = array($element[$field] => $element);
++$this->_resultCounter;
} else {
$result[$element[$field]] = $element;
}
} else {
if ($this->_resultSetMapping->isMixedResult()) {
if ($this->_resultSetMapping->isMixed) {
$result[] = array($element);
++$this->_resultCounter;
} else {

View File

@ -53,13 +53,13 @@ class ObjectHydrator extends AbstractHydrator
/** @override */
protected function _prepare()
{
$this->_isSimpleQuery = $this->_resultSetMapping->getEntityResultCount() <= 1;
$this->_isSimpleQuery = count($this->_resultSetMapping->aliasMap) <= 1;
$this->_allowPartialObjects = $this->_em->getConfiguration()->getAllowPartialObjects();
$this->_identifierMap = array();
$this->_resultPointers = array();
$this->_idTemplate = array();
$this->_resultCounter = 0;
foreach ($this->_resultSetMapping->getAliasMap() as $dqlAlias => $class) {
foreach ($this->_resultSetMapping->aliasMap as $dqlAlias => $class) {
$this->_identifierMap[$dqlAlias] = array();
$this->_resultPointers[$dqlAlias] = array();
$this->_idTemplate[$dqlAlias] = '';
@ -73,8 +73,8 @@ class ObjectHydrator extends AbstractHydrator
$this->_discriminatorMap[$class->name][$value] = $className;
}
}
if ($this->_resultSetMapping->isRelation($dqlAlias)) {
$assoc = $this->_resultSetMapping->getRelation($dqlAlias);
if (isset($this->_resultSetMapping->relationMap[$dqlAlias])) {
$assoc = $this->_resultSetMapping->relationMap[$dqlAlias];
$this->_fetchedAssociations[$assoc->getSourceEntityName()][$assoc->getSourceFieldName()] = true;
if ($mappedByField = $assoc->getMappedByFieldName()) {
$this->_fetchedAssociations[$assoc->getTargetEntityName()][$mappedByField] = true;
@ -97,7 +97,7 @@ class ObjectHydrator extends AbstractHydrator
{
$s = microtime(true);
if ($this->_resultSetMapping->isMixedResult()) {
if ($this->_resultSetMapping->isMixed) {
$result = array();
} else {
$result = new Collection;
@ -226,7 +226,8 @@ class ObjectHydrator extends AbstractHydrator
private function getEntity(array $data, $className)
{
if ($discrColumn = $this->_resultSetMapping->getDiscriminatorColumn($className)) {
if (isset($this->_resultSetMapping->discriminatorColumns[$className])) {
$discrColumn = $this->_resultSetMapping->discriminatorColumns[$className];
$className = $this->_discriminatorMap[$className][$data[$discrColumn]];
unset($data[$discrColumn]);
}
@ -321,18 +322,18 @@ class ObjectHydrator extends AbstractHydrator
// Hydrate the entity data found in the current row.
foreach ($rowData as $dqlAlias => $data) {
$index = false;
$entityName = $this->_resultSetMapping->getClass($dqlAlias)->name;
$entityName = $this->_resultSetMapping->aliasMap[$dqlAlias]->name;
if ($this->_resultSetMapping->hasParentAlias($dqlAlias)) {
if (isset($this->_resultSetMapping->parentAliasMap[$dqlAlias])) {
// It's a joined result
$parent = $this->_resultSetMapping->getParentAlias($dqlAlias);
$relation = $this->_resultSetMapping->getRelation($dqlAlias);
$parent = $this->_resultSetMapping->parentAliasMap[$dqlAlias];
$relation = $this->_resultSetMapping->relationMap[$dqlAlias];
$relationAlias = $relation->getSourceFieldName();
// Get a reference to the right element in the result tree.
// This element will get the associated element attached.
if ($this->_resultSetMapping->isMixedResult() && isset($this->_rootAliases[$parent])) {
if ($this->_resultSetMapping->isMixed && isset($this->_rootAliases[$parent])) {
$key = key(reset($this->_resultPointers));
// TODO: Exception if $key === null ?
$baseElement =& $this->_resultPointers[$parent][$key];
@ -420,7 +421,7 @@ class ObjectHydrator extends AbstractHydrator
if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
$element = $this->getEntity($rowData[$dqlAlias], $entityName);
if ($field = $this->_getCustomIndexField($dqlAlias)) {
if ($this->_resultSetMapping->isMixedResult()) {
if ($this->_resultSetMapping->isMixed) {
$result[] = array(
$this->_classMetadatas[$entityName]
->reflFields[$field]
@ -433,7 +434,7 @@ class ObjectHydrator extends AbstractHydrator
->getValue($element));
}
} else {
if ($this->_resultSetMapping->isMixedResult()) {
if ($this->_resultSetMapping->isMixed) {
$result[] = array($element);
++$this->_resultCounter;
} else {

View File

@ -24,31 +24,35 @@ namespace Doctrine\ORM\Query;
/**
* A ResultSetMapping describes how a result set of an SQL query maps to a Doctrine result.
*
* IMPORTANT NOTE:
* The properties of this class are only public for fast internal READ access.
* Users should use the public methods.
*
* @author Roman Borschel <roman@code-factory.org>
* @since 2.0
*/
class ResultSetMapping
{
/** Whether the result is mixed (contains scalar values together with field values). */
private $_isMixed = false;
public $isMixed = false;
/** Maps alias names to ClassMetadata descriptors. */
private $_aliasMap = array();
public $aliasMap = array();
/** Maps alias names to related association mappings. */
private $_relationMap = array();
public $relationMap = array();
/** Maps alias names to parent alias names. */
private $_parentAliasMap = array();
public $parentAliasMap = array();
/** Maps column names in the result set to field names for each class. */
private $_fieldMappings = array();
public $fieldMappings = array();
/** Maps column names in the result set to the alias to use in the mapped result. */
private $_scalarMappings = array();
public $scalarMappings = array();
/** Maps column names in the result set to the alias they belong to. */
private $_columnOwnerMap = array();
public $columnOwnerMap = array();
/** List of columns in the result set that are used as discriminator columns. */
private $_discriminatorColumns = array();
public $discriminatorColumns = array();
/** Maps alias names to field names that should be used for indexing. */
private $_indexByMap = array();
public $indexByMap = array();
/** A list of columns that should be ignored/skipped during hydration. */
private $_ignoredColumns = array();
public $ignoredColumns = array();
/**
*
@ -58,55 +62,55 @@ class ResultSetMapping
*/
public function addEntityResult($class, $alias)
{
$this->_aliasMap[$alias] = $class;
$this->aliasMap[$alias] = $class;
}
public function setDiscriminatorColumn($className, $alias, $discrColumn)
{
$this->_discriminatorColumns[$className] = $discrColumn;
$this->_columnOwnerMap[$discrColumn] = $alias;
$this->discriminatorColumns[$className] = $discrColumn;
$this->columnOwnerMap[$discrColumn] = $alias;
}
public function getDiscriminatorColumn($className)
{
return isset($this->_discriminatorColumns[$className]) ?
$this->_discriminatorColumns[$className] : null;
return isset($this->discriminatorColumns[$className]) ?
$this->discriminatorColumns[$className] : null;
}
public function addIndexBy($alias, $fieldName)
{
$this->_indexByMap[$alias] = $fieldName;
$this->indexByMap[$alias] = $fieldName;
}
public function hasIndexBy($alias)
{
return isset($this->_indexByMap[$alias]);
return isset($this->indexByMap[$alias]);
}
public function getIndexByField($alias)
{
return $this->_indexByMap[$alias];
return $this->indexByMap[$alias];
}
public function isFieldResult($columnName)
{
return isset($this->_fieldMappings[$columnName]);
return isset($this->fieldMappings[$columnName]);
}
public function addFieldResult($alias, $columnName, $fieldName)
{
$this->_fieldMappings[$columnName] = $fieldName;
$this->_columnOwnerMap[$columnName] = $alias;
if ( ! $this->_isMixed && $this->_scalarMappings) {
$this->_isMixed = true;
$this->fieldMappings[$columnName] = $fieldName;
$this->columnOwnerMap[$columnName] = $alias;
if ( ! $this->isMixed && $this->scalarMappings) {
$this->isMixed = true;
}
}
public function addJoinedEntityResult($class, $alias, $parentAlias, $relation)
{
$this->_aliasMap[$alias] = $class;
$this->_parentAliasMap[$alias] = $parentAlias;
$this->_relationMap[$alias] = $relation;
$this->aliasMap[$alias] = $class;
$this->parentAliasMap[$alias] = $parentAlias;
$this->relationMap[$alias] = $relation;
}
/*public function isDiscriminatorColumn($columnName)
@ -116,9 +120,9 @@ class ResultSetMapping
public function addScalarResult($columnName, $alias)
{
$this->_scalarMappings[$columnName] = $alias;
if ( ! $this->_isMixed && $this->_fieldMappings) {
$this->_isMixed = true;
$this->scalarMappings[$columnName] = $alias;
if ( ! $this->isMixed && $this->fieldMappings) {
$this->isMixed = true;
}
}
@ -127,7 +131,7 @@ class ResultSetMapping
*/
public function isScalarResult($columnName)
{
return isset($this->_scalarMappings[$columnName]);
return isset($this->scalarMappings[$columnName]);
}
/**
@ -136,7 +140,7 @@ class ResultSetMapping
*/
public function getClass($alias)
{
return $this->_aliasMap[$alias];
return $this->aliasMap[$alias];
}
/**
@ -147,7 +151,7 @@ class ResultSetMapping
*/
public function getScalarAlias($columnName)
{
return $this->_scalarMappings[$columnName];
return $this->scalarMappings[$columnName];
}
/**
@ -157,17 +161,17 @@ class ResultSetMapping
*/
public function getOwningClass($columnName)
{
return $this->_aliasMap[$this->_columnOwnerMap[$columnName]];
return $this->aliasMap[$this->columnOwnerMap[$columnName]];
}
public function getRelation($alias)
{
return $this->_relationMap[$alias];
return $this->relationMap[$alias];
}
public function isRelation($alias)
{
return isset($this->_relationMap[$alias]);
return isset($this->relationMap[$alias]);
}
/**
@ -177,7 +181,7 @@ class ResultSetMapping
*/
public function getEntityAlias($columnName)
{
return $this->_columnOwnerMap[$columnName];
return $this->columnOwnerMap[$columnName];
}
/**
@ -187,12 +191,12 @@ class ResultSetMapping
*/
public function getParentAlias($alias)
{
return $this->_parentAliasMap[$alias];
return $this->parentAliasMap[$alias];
}
public function hasParentAlias($alias)
{
return isset($this->_parentAliasMap[$alias]);
return isset($this->parentAliasMap[$alias]);
}
/**
@ -203,32 +207,32 @@ class ResultSetMapping
*/
public function getFieldName($columnName)
{
return $this->_fieldMappings[$columnName];
return $this->fieldMappings[$columnName];
}
public function getAliasMap()
{
return $this->_aliasMap;
return $this->aliasMap;
}
public function getEntityResultCount()
{
return count($this->_aliasMap);
return count($this->aliasMap);
}
public function isMixedResult()
{
return $this->_isMixed;
return $this->isMixed;
}
public function addIgnoredColumn($columnName)
{
$this->_ignoredColumns[$columnName] = true;
$this->ignoredColumns[$columnName] = true;
}
public function isIgnoredColumn($columnName)
{
return isset($this->_ignoredColumns[$columnName]);
return isset($this->ignoredColumns[$columnName]);
}
}

View File

@ -679,76 +679,4 @@ class ObjectHydratorTest extends HydrationTest
++$rowNum;
}
}
/**
* select u.id, u.status, p.phonenumber, upper(u.name) nameUpper from User u
* join u.phonenumbers p
* =
* select u.id, u.status, p.phonenumber, upper(u.name) as u__0 from USERS u
* INNER JOIN PHONENUMBERS p ON u.id = p.user_id
*
* @dataProvider hydrationModeProvider
*/
public function testNewHydrationMixedQueryFetchJoinPerformance()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u');
/*$rsm->addJoinedEntityResult(
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'),
'p',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers')
);*/
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addFieldResult('u', 'u__username', 'username');
$rsm->addFieldResult('u', 'u__name', 'name');
//$rsm->addScalarResult('sclr0', 'nameUpper');
//$rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
// Faked result set
$resultSet = array(
//row1
array(
'u__id' => '1',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
//'sclr0' => 'ROMANB',
//'p__phonenumber' => '42',
),
array(
'u__id' => '1',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
//'sclr0' => 'ROMANB',
//'p__phonenumber' => '43',
),
array(
'u__id' => '2',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
//'sclr0' => 'JWAGE',
//'p__phonenumber' => '91'
)
);
for ($i = 4; $i < 10000; ++$i) {
$resultSet[] = array(
'u__id' => $i,
'u__status' => 'developer',
'u__username' => 'jwage',
'u__name' => 'Jonathan',
//'sclr0' => 'JWAGE' . $i,
//'p__phonenumber' => '91'
);
}
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$result = $hydrator->hydrateAll($stmt, $rsm);
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace Doctrine\Tests\ORM\Performance;
if (!defined('PHPUnit_MAIN_METHOD')) {
define('PHPUnit_MAIN_METHOD', 'Orm_Performance_AllTests::main');
}
require_once __DIR__ . '/../../TestInit.php';
class AllTests
{
public static function main()
{
\PHPUnit_TextUI_TestRunner::run(self::suite());
}
public static function suite()
{
$suite = new \Doctrine\Tests\DoctrineTestSuite('Doctrine Orm Performance');
$suite->addTestSuite('Doctrine\Tests\ORM\Performance\HydrationPerformanceTest');
return $suite;
}
}
if (PHPUnit_MAIN_METHOD == 'Orm_Performance_AllTests::main') {
AllTests::main();
}

View File

@ -0,0 +1,268 @@
<?php
namespace Doctrine\Tests\ORM\Performance;
require_once __DIR__ . '/../../TestInit.php';
use Doctrine\Tests\Mocks\HydratorMockStatement;
use Doctrine\ORM\Query\ResultSetMapping;
/**
* Tests to prevent serious performance regressions.
*
* IMPORTANT: Be sure to run these tests withoug xdebug or similar tools that
* seriously degrade performance.
*
* @author robo
*/
class HydrationPerformanceTest extends \Doctrine\Tests\OrmPerformanceTestCase
{
/**
* Times for comparison:
*
* [romanb: 10000 rows => 1.8 seconds]
*
* MAXIMUM TIME: 3 seconds
*/
public function testNewHydrationSimpleQueryArrayHydrationPerformance()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u');
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addFieldResult('u', 'u__username', 'username');
$rsm->addFieldResult('u', 'u__name', 'name');
// Faked result set
$resultSet = array(
//row1
array(
'u__id' => '1',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
),
array(
'u__id' => '1',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
),
array(
'u__id' => '2',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
)
);
for ($i = 4; $i < 10000; ++$i) {
$resultSet[] = array(
'u__id' => $i,
'u__status' => 'developer',
'u__username' => 'jwage',
'u__name' => 'Jonathan',
);
}
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$this->setMaxRunningTime(3);
$result = $hydrator->hydrateAll($stmt, $rsm);
}
/**
* Times for comparison:
*
* [romanb: 10000 rows => 3.0 seconds]
*
* MAXIMUM TIME: 4 seconds
*/
public function testNewHydrationMixedQueryFetchJoinArrayHydrationPerformance()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u');
$rsm->addJoinedEntityResult(
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'),
'p',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers')
);
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addFieldResult('u', 'u__username', 'username');
$rsm->addFieldResult('u', 'u__name', 'name');
$rsm->addScalarResult('sclr0', 'nameUpper');
$rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
// Faked result set
$resultSet = array(
//row1
array(
'u__id' => '1',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
'sclr0' => 'ROMANB',
'p__phonenumber' => '42',
),
array(
'u__id' => '1',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
'sclr0' => 'ROMANB',
'p__phonenumber' => '43',
),
array(
'u__id' => '2',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
'sclr0' => 'JWAGE',
'p__phonenumber' => '91'
)
);
for ($i = 4; $i < 10000; ++$i) {
$resultSet[] = array(
'u__id' => $i,
'u__status' => 'developer',
'u__username' => 'jwage',
'u__name' => 'Jonathan',
'sclr0' => 'JWAGE' . $i,
'p__phonenumber' => '91'
);
}
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ArrayHydrator($this->_em);
$this->setMaxRunningTime(4);
$result = $hydrator->hydrateAll($stmt, $rsm);
}
/**
* [romanb: 10000 rows => 3.4 seconds]
*
* MAXIMUM TIME: 4 seconds
*/
public function testSimpleQueryObjectHydrationPerformance()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u');
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addFieldResult('u', 'u__username', 'username');
$rsm->addFieldResult('u', 'u__name', 'name');
// Faked result set
$resultSet = array(
//row1
array(
'u__id' => '1',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
),
array(
'u__id' => '1',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
),
array(
'u__id' => '2',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
)
);
for ($i = 4; $i < 10000; ++$i) {
$resultSet[] = array(
'u__id' => $i,
'u__status' => 'developer',
'u__username' => 'jwage',
'u__name' => 'Jonathan',
);
}
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$this->setMaxRunningTime(4);
$result = $hydrator->hydrateAll($stmt, $rsm);
}
/**
* [romanb: 2000 rows => 3.1 seconds]
*
* MAXIMUM TIME: 4 seconds
*/
public function testMixedQueryFetchJoinObjectHydrationPerformance()
{
$rsm = new ResultSetMapping;
$rsm->addEntityResult($this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser'), 'u');
$rsm->addJoinedEntityResult(
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsPhonenumber'),
'p',
'u',
$this->_em->getClassMetadata('Doctrine\Tests\Models\CMS\CmsUser')->getAssociationMapping('phonenumbers')
);
$rsm->addFieldResult('u', 'u__id', 'id');
$rsm->addFieldResult('u', 'u__status', 'status');
$rsm->addFieldResult('u', 'u__username', 'username');
$rsm->addFieldResult('u', 'u__name', 'name');
$rsm->addScalarResult('sclr0', 'nameUpper');
$rsm->addFieldResult('p', 'p__phonenumber', 'phonenumber');
// Faked result set
$resultSet = array(
//row1
array(
'u__id' => '1',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
'sclr0' => 'ROMANB',
'p__phonenumber' => '42',
),
array(
'u__id' => '1',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
'sclr0' => 'ROMANB',
'p__phonenumber' => '43',
),
array(
'u__id' => '2',
'u__status' => 'developer',
'u__username' => 'romanb',
'u__name' => 'Roman',
'sclr0' => 'JWAGE',
'p__phonenumber' => '91'
)
);
for ($i = 4; $i < 2000; ++$i) {
$resultSet[] = array(
'u__id' => $i,
'u__status' => 'developer',
'u__username' => 'jwage',
'u__name' => 'Jonathan',
'sclr0' => 'JWAGE' . $i,
'p__phonenumber' => '91'
);
}
$stmt = new HydratorMockStatement($resultSet);
$hydrator = new \Doctrine\ORM\Internal\Hydration\ObjectHydrator($this->_em);
$this->setMaxRunningTime(4);
$result = $hydrator->hydrateAll($stmt, $rsm);
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace Doctrine\Tests;
/**
* Description of DoctrinePerformanceTestCase
*
* @author robo
*/
class OrmPerformanceTestCase extends OrmTestCase
{
protected $_em;
protected function setUp()
{
parent::setUp();
$this->_em = $this->_getTestEntityManager();
}
/**
* @var integer
*/
protected $maxRunningTime = 0;
/**
*/
protected function runTest()
{
$s = microtime(true);
parent::runTest();
$time = microtime(true) - $s;
if ($this->maxRunningTime != 0 && $time > $this->maxRunningTime) {
$this->fail(
sprintf(
'expected running time: <= %s but was: %s',
$this->maxRunningTime,
$time
)
);
}
}
/**
* @param integer $maxRunningTime
* @throws InvalidArgumentException
* @since Method available since Release 2.3.0
*/
public function setMaxRunningTime($maxRunningTime)
{
if (is_integer($maxRunningTime) && $maxRunningTime >= 0) {
$this->maxRunningTime = $maxRunningTime;
} else {
throw new \InvalidArgumentException;
}
}
/**
* @return integer
* @since Method available since Release 2.3.0
*/
public function getMaxRunningTime()
{
return $this->maxRunningTime;
}
}