[2.0] Started adding performance regression tests. More object hydration performance improvements.
This commit is contained in:
parent
e79c45f9ac
commit
eea4391598
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
31
tests/Doctrine/Tests/ORM/Performance/AllTests.php
Normal file
31
tests/Doctrine/Tests/ORM/Performance/AllTests.php
Normal 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();
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
68
tests/Doctrine/Tests/OrmPerformanceTestCase.php
Normal file
68
tests/Doctrine/Tests/OrmPerformanceTestCase.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user