Przeglądaj źródła

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

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@2496 a333f486-631f-4898-b8df-5754b55c2be0
romainq 12 lat temu
rodzic
commit
cc718b70ef

+ 28 - 2
core/expression.class.inc.php

@@ -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)

+ 9 - 13
core/metamodel.class.php

@@ -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

+ 1 - 1
core/querybuildercontext.class.inc.php

@@ -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();

+ 18 - 23
core/sqlquery.class.inc.php

@@ -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)
 		{