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

View File

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

View File

@ -53,13 +53,13 @@ class ObjectHydrator extends AbstractHydrator
/** @override */ /** @override */
protected function _prepare() protected function _prepare()
{ {
$this->_isSimpleQuery = $this->_resultSetMapping->getEntityResultCount() <= 1; $this->_isSimpleQuery = count($this->_resultSetMapping->aliasMap) <= 1;
$this->_allowPartialObjects = $this->_em->getConfiguration()->getAllowPartialObjects(); $this->_allowPartialObjects = $this->_em->getConfiguration()->getAllowPartialObjects();
$this->_identifierMap = array(); $this->_identifierMap = array();
$this->_resultPointers = array(); $this->_resultPointers = array();
$this->_idTemplate = array(); $this->_idTemplate = array();
$this->_resultCounter = 0; $this->_resultCounter = 0;
foreach ($this->_resultSetMapping->getAliasMap() as $dqlAlias => $class) { foreach ($this->_resultSetMapping->aliasMap as $dqlAlias => $class) {
$this->_identifierMap[$dqlAlias] = array(); $this->_identifierMap[$dqlAlias] = array();
$this->_resultPointers[$dqlAlias] = array(); $this->_resultPointers[$dqlAlias] = array();
$this->_idTemplate[$dqlAlias] = ''; $this->_idTemplate[$dqlAlias] = '';
@ -73,8 +73,8 @@ class ObjectHydrator extends AbstractHydrator
$this->_discriminatorMap[$class->name][$value] = $className; $this->_discriminatorMap[$class->name][$value] = $className;
} }
} }
if ($this->_resultSetMapping->isRelation($dqlAlias)) { if (isset($this->_resultSetMapping->relationMap[$dqlAlias])) {
$assoc = $this->_resultSetMapping->getRelation($dqlAlias); $assoc = $this->_resultSetMapping->relationMap[$dqlAlias];
$this->_fetchedAssociations[$assoc->getSourceEntityName()][$assoc->getSourceFieldName()] = true; $this->_fetchedAssociations[$assoc->getSourceEntityName()][$assoc->getSourceFieldName()] = true;
if ($mappedByField = $assoc->getMappedByFieldName()) { if ($mappedByField = $assoc->getMappedByFieldName()) {
$this->_fetchedAssociations[$assoc->getTargetEntityName()][$mappedByField] = true; $this->_fetchedAssociations[$assoc->getTargetEntityName()][$mappedByField] = true;
@ -97,7 +97,7 @@ class ObjectHydrator extends AbstractHydrator
{ {
$s = microtime(true); $s = microtime(true);
if ($this->_resultSetMapping->isMixedResult()) { if ($this->_resultSetMapping->isMixed) {
$result = array(); $result = array();
} else { } else {
$result = new Collection; $result = new Collection;
@ -226,7 +226,8 @@ class ObjectHydrator extends AbstractHydrator
private function getEntity(array $data, $className) 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]]; $className = $this->_discriminatorMap[$className][$data[$discrColumn]];
unset($data[$discrColumn]); unset($data[$discrColumn]);
} }
@ -321,18 +322,18 @@ class ObjectHydrator extends AbstractHydrator
// Hydrate the entity data found in the current row. // Hydrate the entity data found in the current row.
foreach ($rowData as $dqlAlias => $data) { foreach ($rowData as $dqlAlias => $data) {
$index = false; $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 // It's a joined result
$parent = $this->_resultSetMapping->getParentAlias($dqlAlias); $parent = $this->_resultSetMapping->parentAliasMap[$dqlAlias];
$relation = $this->_resultSetMapping->getRelation($dqlAlias); $relation = $this->_resultSetMapping->relationMap[$dqlAlias];
$relationAlias = $relation->getSourceFieldName(); $relationAlias = $relation->getSourceFieldName();
// Get a reference to the right element in the result tree. // Get a reference to the right element in the result tree.
// This element will get the associated element attached. // 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)); $key = key(reset($this->_resultPointers));
// TODO: Exception if $key === null ? // TODO: Exception if $key === null ?
$baseElement =& $this->_resultPointers[$parent][$key]; $baseElement =& $this->_resultPointers[$parent][$key];
@ -420,7 +421,7 @@ class ObjectHydrator extends AbstractHydrator
if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) { if ($this->_isSimpleQuery || ! isset($this->_identifierMap[$dqlAlias][$id[$dqlAlias]])) {
$element = $this->getEntity($rowData[$dqlAlias], $entityName); $element = $this->getEntity($rowData[$dqlAlias], $entityName);
if ($field = $this->_getCustomIndexField($dqlAlias)) { if ($field = $this->_getCustomIndexField($dqlAlias)) {
if ($this->_resultSetMapping->isMixedResult()) { if ($this->_resultSetMapping->isMixed) {
$result[] = array( $result[] = array(
$this->_classMetadatas[$entityName] $this->_classMetadatas[$entityName]
->reflFields[$field] ->reflFields[$field]
@ -433,7 +434,7 @@ class ObjectHydrator extends AbstractHydrator
->getValue($element)); ->getValue($element));
} }
} else { } else {
if ($this->_resultSetMapping->isMixedResult()) { if ($this->_resultSetMapping->isMixed) {
$result[] = array($element); $result[] = array($element);
++$this->_resultCounter; ++$this->_resultCounter;
} else { } 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. * 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> * @author Roman Borschel <roman@code-factory.org>
* @since 2.0 * @since 2.0
*/ */
class ResultSetMapping class ResultSetMapping
{ {
/** Whether the result is mixed (contains scalar values together with field values). */ /** Whether the result is mixed (contains scalar values together with field values). */
private $_isMixed = false; public $isMixed = false;
/** Maps alias names to ClassMetadata descriptors. */ /** Maps alias names to ClassMetadata descriptors. */
private $_aliasMap = array(); public $aliasMap = array();
/** Maps alias names to related association mappings. */ /** Maps alias names to related association mappings. */
private $_relationMap = array(); public $relationMap = array();
/** Maps alias names to parent alias names. */ /** 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. */ /** 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. */ /** 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. */ /** 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. */ /** 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. */ /** 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. */ /** 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) public function addEntityResult($class, $alias)
{ {
$this->_aliasMap[$alias] = $class; $this->aliasMap[$alias] = $class;
} }
public function setDiscriminatorColumn($className, $alias, $discrColumn) public function setDiscriminatorColumn($className, $alias, $discrColumn)
{ {
$this->_discriminatorColumns[$className] = $discrColumn; $this->discriminatorColumns[$className] = $discrColumn;
$this->_columnOwnerMap[$discrColumn] = $alias; $this->columnOwnerMap[$discrColumn] = $alias;
} }
public function getDiscriminatorColumn($className) public function getDiscriminatorColumn($className)
{ {
return isset($this->_discriminatorColumns[$className]) ? return isset($this->discriminatorColumns[$className]) ?
$this->_discriminatorColumns[$className] : null; $this->discriminatorColumns[$className] : null;
} }
public function addIndexBy($alias, $fieldName) public function addIndexBy($alias, $fieldName)
{ {
$this->_indexByMap[$alias] = $fieldName; $this->indexByMap[$alias] = $fieldName;
} }
public function hasIndexBy($alias) public function hasIndexBy($alias)
{ {
return isset($this->_indexByMap[$alias]); return isset($this->indexByMap[$alias]);
} }
public function getIndexByField($alias) public function getIndexByField($alias)
{ {
return $this->_indexByMap[$alias]; return $this->indexByMap[$alias];
} }
public function isFieldResult($columnName) public function isFieldResult($columnName)
{ {
return isset($this->_fieldMappings[$columnName]); return isset($this->fieldMappings[$columnName]);
} }
public function addFieldResult($alias, $columnName, $fieldName) public function addFieldResult($alias, $columnName, $fieldName)
{ {
$this->_fieldMappings[$columnName] = $fieldName; $this->fieldMappings[$columnName] = $fieldName;
$this->_columnOwnerMap[$columnName] = $alias; $this->columnOwnerMap[$columnName] = $alias;
if ( ! $this->_isMixed && $this->_scalarMappings) { if ( ! $this->isMixed && $this->scalarMappings) {
$this->_isMixed = true; $this->isMixed = true;
} }
} }
public function addJoinedEntityResult($class, $alias, $parentAlias, $relation) public function addJoinedEntityResult($class, $alias, $parentAlias, $relation)
{ {
$this->_aliasMap[$alias] = $class; $this->aliasMap[$alias] = $class;
$this->_parentAliasMap[$alias] = $parentAlias; $this->parentAliasMap[$alias] = $parentAlias;
$this->_relationMap[$alias] = $relation; $this->relationMap[$alias] = $relation;
} }
/*public function isDiscriminatorColumn($columnName) /*public function isDiscriminatorColumn($columnName)
@ -116,9 +120,9 @@ class ResultSetMapping
public function addScalarResult($columnName, $alias) public function addScalarResult($columnName, $alias)
{ {
$this->_scalarMappings[$columnName] = $alias; $this->scalarMappings[$columnName] = $alias;
if ( ! $this->_isMixed && $this->_fieldMappings) { if ( ! $this->isMixed && $this->fieldMappings) {
$this->_isMixed = true; $this->isMixed = true;
} }
} }
@ -127,7 +131,7 @@ class ResultSetMapping
*/ */
public function isScalarResult($columnName) public function isScalarResult($columnName)
{ {
return isset($this->_scalarMappings[$columnName]); return isset($this->scalarMappings[$columnName]);
} }
/** /**
@ -136,7 +140,7 @@ class ResultSetMapping
*/ */
public function getClass($alias) public function getClass($alias)
{ {
return $this->_aliasMap[$alias]; return $this->aliasMap[$alias];
} }
/** /**
@ -147,7 +151,7 @@ class ResultSetMapping
*/ */
public function getScalarAlias($columnName) public function getScalarAlias($columnName)
{ {
return $this->_scalarMappings[$columnName]; return $this->scalarMappings[$columnName];
} }
/** /**
@ -157,17 +161,17 @@ class ResultSetMapping
*/ */
public function getOwningClass($columnName) public function getOwningClass($columnName)
{ {
return $this->_aliasMap[$this->_columnOwnerMap[$columnName]]; return $this->aliasMap[$this->columnOwnerMap[$columnName]];
} }
public function getRelation($alias) public function getRelation($alias)
{ {
return $this->_relationMap[$alias]; return $this->relationMap[$alias];
} }
public function isRelation($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) public function getEntityAlias($columnName)
{ {
return $this->_columnOwnerMap[$columnName]; return $this->columnOwnerMap[$columnName];
} }
/** /**
@ -187,12 +191,12 @@ class ResultSetMapping
*/ */
public function getParentAlias($alias) public function getParentAlias($alias)
{ {
return $this->_parentAliasMap[$alias]; return $this->parentAliasMap[$alias];
} }
public function hasParentAlias($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) public function getFieldName($columnName)
{ {
return $this->_fieldMappings[$columnName]; return $this->fieldMappings[$columnName];
} }
public function getAliasMap() public function getAliasMap()
{ {
return $this->_aliasMap; return $this->aliasMap;
} }
public function getEntityResultCount() public function getEntityResultCount()
{ {
return count($this->_aliasMap); return count($this->aliasMap);
} }
public function isMixedResult() public function isMixedResult()
{ {
return $this->_isMixed; return $this->isMixed;
} }
public function addIgnoredColumn($columnName) public function addIgnoredColumn($columnName)
{ {
$this->_ignoredColumns[$columnName] = true; $this->ignoredColumns[$columnName] = true;
} }
public function isIgnoredColumn($columnName) 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; ++$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;
}
}