Optimization of SQL queries: fixed two issues (SELECT to track object linked to... and SELECT ExternalUser)

SVN:trunk[2496]
This commit is contained in:
Romain Quetiez
2012-12-03 17:00:38 +00:00
parent fe27ee4f22
commit 90bc24d5c0
4 changed files with 56 additions and 39 deletions

View File

@@ -1121,13 +1121,20 @@ class QueryBuilderExpressions
protected $m_aSelectExpr;
protected $m_aGroupByExpr;
protected $m_aJoinFields;
protected $m_aClassIds;
public function __construct($oCondition, $aGroupByExpr = null)
public function __construct($oSearch, $aGroupByExpr = null)
{
$this->m_oConditionExpr = $oCondition;
$this->m_oConditionExpr = $oSearch->GetCriteria();
$this->m_aSelectExpr = array();
$this->m_aGroupByExpr = $aGroupByExpr;
$this->m_aJoinFields = array();
$this->m_aClassIds = array();
foreach($oSearch->GetJoinedClasses() as $sClassAlias => $sClass)
{
$this->m_aClassIds[$sClassAlias] = new FieldExpression('id', $sClassAlias);
}
}
public function GetSelect()
@@ -1166,6 +1173,20 @@ class QueryBuilderExpressions
array_push($this->m_aJoinFields, $oExpression);
}
/**
* Get tables representing the queried objects
* Could be further optimized: when the first join is an outer join, then the rest can be omitted
*/
public function GetMandatoryTables(&$aTables = null)
{
if (is_null($aTables)) $aTables = array();
foreach($this->m_aClassIds as $sClass => $oExpression)
{
$oExpression->CollectUsedParents($aTables);
}
}
public function GetUnresolvedFields($sAlias, &$aUnresolved)
{
$this->m_oConditionExpr->GetUnresolvedFields($sAlias, $aUnresolved);
@@ -1204,6 +1225,11 @@ class QueryBuilderExpressions
{
$this->m_aJoinFields[$index] = $oExpression->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
}
foreach($this->m_aClassIds as $sClass => $oExpression)
{
$this->m_aClassIds[$sClass] = $oExpression->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
}
}
public function RenameParam($sOldName, $sNewName)

View File

@@ -2290,7 +2290,8 @@ abstract class MetaModel
// Simplify the query if just getting the count
$oSelect->SetSelect(array());
}
$oSelect->OptimizeJoins();
$oBuild->m_oQBExpressions->GetMandatoryTables($aMandatoryTables);
$oSelect->OptimizeJoins($aMandatoryTables);
}
$oKPI->ComputeStats('MakeQuery (select)', $sOqlQuery);
@@ -2504,7 +2505,6 @@ abstract class MetaModel
{
// default to the whole list of attributes + the very std id/finalclass
$oBuild->m_oQBExpressions->AddSelect($sClassAlias.'id', new FieldExpression('id', $sClassAlias));
if (is_null($aAttToLoad) || !array_key_exists($sClassAlias, $aAttToLoad))
{
$aAttList = self::ListAttributeDefs($sClass);
@@ -2798,19 +2798,15 @@ abstract class MetaModel
// 1/a - Get the key and friendly name
//
// We need one pkey to be the key, let's take the one corresponding to the root class
// (used to be based on the leaf, then moved to the root class... now back to the leaf for optimization concerns)
// We need one pkey to be the key, let's take the first one available
$oSelectedIdField = null;
if ($sTableClass == $sTargetClass)
{
$oIdField = new FieldExpressionResolved(self::DBGetKey($sTableClass), $sTableAlias);
$aTranslation[$sTargetAlias]['id'] = $oIdField;
$oIdField = new FieldExpressionResolved(self::DBGetKey($sTableClass), $sTableAlias);
$aTranslation[$sTargetAlias]['id'] = $oIdField;
if ($bIsOnQueriedClass)
{
// Add this field to the list of queried fields (required for the COUNT to work fine)
$oSelectedIdField = $oIdField;
}
if ($bIsOnQueriedClass)
{
// Add this field to the list of queried fields (required for the COUNT to work fine)
$oSelectedIdField = $oIdField;
}
// 1/b - Get the other attributes

View File

@@ -35,7 +35,7 @@ class QueryBuilderContext
public function __construct($oFilter, $aModifierProperties, $aGroupByExpr = null)
{
$this->m_oRootFilter = $oFilter;
$this->m_oQBExpressions = new QueryBuilderExpressions($oFilter->GetCriteria(), $aGroupByExpr);
$this->m_oQBExpressions = new QueryBuilderExpressions($oFilter, $aGroupByExpr);
$this->m_aClassAliases = $oFilter->GetJoinedClasses();
$this->m_aTableAliases = array();

View File

@@ -597,12 +597,12 @@ class SQLQuery
return $this->m_sTableAlias;
}
public function OptimizeJoins($aUsedTables = null)
public function OptimizeJoins($aUsedTables, $bTopCall = true)
{
if (is_null($aUsedTables))
if ($bTopCall)
{
// Top call: build the list of tables absolutely required to perform the query
$aUsedTables = $this->CollectUsedTables();
// Top call: complete the list of tables absolutely required to perform the right query
$this->CollectUsedTables($aUsedTables);
}
$aToDiscard = array();
@@ -610,7 +610,7 @@ class SQLQuery
{
$oSQLQuery = $aJoinInfo["select"];
$sTableAlias = $oSQLQuery->GetTableAlias();
if ($oSQLQuery->OptimizeJoins($aUsedTables) && !array_key_exists($sTableAlias, $aUsedTables))
if ($oSQLQuery->OptimizeJoins($aUsedTables, false) && !array_key_exists($sTableAlias, $aUsedTables))
{
$aToDiscard[] = $i;
}
@@ -623,29 +623,24 @@ class SQLQuery
return (count($this->m_aJoinSelects) == 0);
}
protected function CollectUsedTables(&$aTables = null)
protected function CollectUsedTables(&$aTables)
{
if (is_null($aTables))
$this->m_oConditionExpr->CollectUsedParents($aTables);
foreach($this->m_aFields as $sFieldAlias => $oField)
{
$aTables = array();
$this->m_oConditionExpr->CollectUsedParents($aTables);
foreach($this->m_aFields as $sFieldAlias => $oField)
$oField->CollectUsedParents($aTables);
}
if ($this->m_aGroupBy)
{
foreach($this->m_aGroupBy as $sAlias => $oExpression)
{
$oField->CollectUsedParents($aTables);
}
if ($this->m_aGroupBy)
{
foreach($this->m_aGroupBy as $sAlias => $oExpression)
{
$oExpression->CollectUsedParents($aTables);
}
}
if (!is_null($this->m_oSelectedIdField))
{
$this->m_oSelectedIdField->CollectUsedParents($aTables);
$oExpression->CollectUsedParents($aTables);
}
}
if (!is_null($this->m_oSelectedIdField))
{
$this->m_oSelectedIdField->CollectUsedParents($aTables);
}
foreach ($this->m_aJoinSelects as $i => $aJoinInfo)
{