mirror of
				https://github.com/apache/cloudstack.git
				synced 2025-10-26 08:42:29 +01:00 
			
		
		
		
	CLOUDSTACK-10065: Optimize SQL queries in listTemplate API to improve performance (#2260)
The db queries in listTemplateAPI could be optimized to get unique results from the database which could help in reducing the listTemplate API response time.
This commit is contained in:
		
							parent
							
								
									ebb7a5279d
								
							
						
					
					
						commit
						7253969088
					
				| @ -276,4 +276,6 @@ public interface GenericDao<T, ID extends Serializable> { | ||||
|     Pair<List<T>, Integer> searchAndDistinctCount(final SearchCriteria<T> sc, final Filter filter); | ||||
| 
 | ||||
|     Map<String, Attribute> getAllAttributes(); | ||||
| 
 | ||||
|     Pair<List<T>, Integer> searchAndDistinctCount(final SearchCriteria<T> sc, final Filter filter, final String[] distinctColumns); | ||||
| } | ||||
|  | ||||
| @ -44,7 +44,7 @@ import java.util.Map; | ||||
| import java.util.TimeZone; | ||||
| import java.util.UUID; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| 
 | ||||
| import com.google.common.base.Strings; | ||||
| import javax.naming.ConfigurationException; | ||||
| import javax.persistence.AttributeOverride; | ||||
| import javax.persistence.Column; | ||||
| @ -1326,6 +1326,14 @@ public abstract class GenericDaoBase<T, ID extends Serializable> extends Compone | ||||
|         return new Pair<List<T>, Integer>(objects, count); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @DB() | ||||
|     public Pair<List<T>, Integer> searchAndDistinctCount(final SearchCriteria<T> sc, final Filter filter, final String[] distinctColumns) { | ||||
|         List<T> objects = search(sc, filter, null, false); | ||||
|         Integer count = getDistinctCount(sc, distinctColumns); | ||||
|         return new Pair<List<T>, Integer>(objects, count); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @DB() | ||||
|     public List<T> search(final SearchCriteria<T> sc, final Filter filter, final boolean enableQueryCache) { | ||||
| @ -1927,6 +1935,52 @@ public abstract class GenericDaoBase<T, ID extends Serializable> extends Compone | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public Integer getDistinctCount(SearchCriteria<T> sc, String[] distinctColumns) { | ||||
|         String clause = sc != null ? sc.getWhereClause() : null; | ||||
|         if (Strings.isNullOrEmpty(clause)) { | ||||
|             clause = null; | ||||
|         } | ||||
| 
 | ||||
|         final StringBuilder str = createDistinctSelect(sc, clause != null, distinctColumns); | ||||
|         if (clause != null) { | ||||
|             str.append(clause); | ||||
|         } | ||||
| 
 | ||||
|         Collection<JoinBuilder<SearchCriteria<?>>> joins = null; | ||||
|         if (sc != null) { | ||||
|             joins = sc.getJoins(); | ||||
|             if (joins != null) { | ||||
|                 addJoins(str, joins); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         final TransactionLegacy txn = TransactionLegacy.currentTxn(); | ||||
|         final String sql = "SELECT COUNT(*) FROM (" + str.toString() + ") AS tmp"; | ||||
| 
 | ||||
|         try (PreparedStatement pstmt = txn.prepareAutoCloseStatement(sql)) { | ||||
|             int i = 1; | ||||
|             if (clause != null) { | ||||
|                 for (final Pair<Attribute, Object> value : sc.getValues()) { | ||||
|                     prepareAttribute(i++, pstmt, value.first(), value.second()); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (joins != null) { | ||||
|                 i = addJoinAttributes(i, pstmt, joins); | ||||
|             } | ||||
| 
 | ||||
|             final ResultSet rs = pstmt.executeQuery(); | ||||
|             while (rs.next()) { | ||||
|                 return rs.getInt(1); | ||||
|             } | ||||
|             return 0; | ||||
|         } catch (final SQLException e) { | ||||
|             throw new CloudRuntimeException("DB Exception in executing: " + sql, e); | ||||
|         } catch (final Throwable e) { | ||||
|             throw new CloudRuntimeException("Caught exception in : " + sql, e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public Integer getCount(SearchCriteria<T> sc) { | ||||
|         String clause = sc != null ? sc.getWhereClause() : null; | ||||
|         if (clause != null && clause.length() == 0) { | ||||
| @ -2013,4 +2067,18 @@ public abstract class GenericDaoBase<T, ID extends Serializable> extends Compone | ||||
|         Integer count = getCount(sc); | ||||
|         return new Pair<List<T>, Integer>(objects, count); | ||||
|     } | ||||
| 
 | ||||
|     @DB() | ||||
|     protected StringBuilder createDistinctSelect(SearchCriteria<?> sc, final boolean whereClause, String[] distinctColumns) { | ||||
|         final SqlGenerator generator = new SqlGenerator(_entityBeanType); | ||||
|         String distinctSql = generator.buildDistinctSql(distinctColumns); | ||||
| 
 | ||||
|         StringBuilder sql = new StringBuilder(distinctSql); | ||||
| 
 | ||||
|         if (!whereClause) { | ||||
|             sql.delete(sql.length() - (_discriminatorClause == null ? 6 : 4), sql.length()); | ||||
|         } | ||||
| 
 | ||||
|         return sql; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -680,4 +680,20 @@ public class SqlGenerator { | ||||
| 
 | ||||
|         return sql.append("SELECT DISTINCT id FROM ").append(buildTableReferences()).append(" WHERE ").append(buildDiscriminatorClause().first()).toString(); | ||||
|     } | ||||
| 
 | ||||
|     public String buildDistinctSql(String[] distinctColumnNames) { | ||||
|         StringBuilder sbColumn = new StringBuilder(); | ||||
| 
 | ||||
|         if (distinctColumnNames != null && distinctColumnNames.length > 0) { | ||||
|             for (String columnName : distinctColumnNames) { | ||||
|                 sbColumn.append(columnName).append(", "); | ||||
|             } | ||||
|             sbColumn.delete(sbColumn.length() - 2, sbColumn.length()); | ||||
|         } else { | ||||
|             sbColumn.append("*"); | ||||
|         } | ||||
| 
 | ||||
|         StringBuilder sql = new StringBuilder(); | ||||
|         return sql.append("SELECT DISTINCT " + sbColumn.toString() + " FROM ").append(buildTableReferences()).append(" WHERE ").append(buildDiscriminatorClause().first()).toString(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -3383,7 +3383,8 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q | ||||
|             uniqueTmplPair = _templateJoinDao.searchIncludingRemovedAndCount(sc, searchFilter); | ||||
|         } else { | ||||
|             sc.addAnd("templateState", SearchCriteria.Op.IN, new State[]{State.Active, State.UploadAbandoned, State.UploadError, State.NotUploaded, State.UploadInProgress}); | ||||
|             uniqueTmplPair = _templateJoinDao.searchAndCount(sc, searchFilter); | ||||
|             final String[] distinctColumns = {"temp_zone_pair"}; | ||||
|             uniqueTmplPair = _templateJoinDao.searchAndDistinctCount(sc, searchFilter, distinctColumns); | ||||
|         } | ||||
| 
 | ||||
|         Integer count = uniqueTmplPair.second(); | ||||
|  | ||||
| @ -278,6 +278,11 @@ public class MockUsageEventDao implements UsageEventDao{ | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public Pair<List<UsageEventVO>, Integer> searchAndDistinctCount(SearchCriteria<UsageEventVO> sc, Filter filter, String[] distinctColumns) { | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public List<UsageEventVO> listLatestEvents(Date endDate) { | ||||
|         return null; | ||||
| @ -303,5 +308,4 @@ public class MockUsageEventDao implements UsageEventDao{ | ||||
|     public void saveDetails(long eventId, Map<String, String> details) { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user