Как оптимизировать запрос с большим количеством агрегатов - PullRequest
0 голосов
/ 19 июля 2011

Как мне оптимизировать этот запрос? Сейчас он работает слишком медленно ~ 10 секунд. Полная информация ниже:

SELECT ProjectName, 
       Actuals_YTD, 
       Rem_Forecast, 
       Total_Forecast, 
       Approved_Budget, 
       Variance, 
       Variance_Percentage, 
       ProjectComments, 
       VersionType, 
       ModifiedDate 
FROM (SELECT pd.ProjectId, 
             pd.ProjectName, 
             SUM(CASE WHEN RPD.PROJECTMONTH_TO_DATE(base.ProjectMonth) <= '06/01/2011' THEN feb.USDactualamount ELSE 0.0 END) AS Actuals_YTD, 
             SUM(CASE WHEN RPD.PROJECTMONTH_TO_DATE(base.ProjectMonth) > '06/01/2011' THEN feb.forecastusd ELSE 0.0 END) AS Rem_Forecast, 
             ((SUM(CASE WHEN RPD.PROJECTMONTH_TO_DATE(base.ProjectMonth) <= '06/01/2011' THEN feb.USDactualamount ELSE 0.0 END)) + (SUM(CASE WHEN RPD.PROJECTMONTH_TO_DATE(base.ProjectMonth) > '06/01/2011' then feb.forecastusd else 0.0 end))) AS Total_Forecast, 
             SUM(COALESCE((feb.REVISEDPLANUSD),0)) AS Approved_Budget, 
             ((SUM(CASE WHEN RPD.PROJECTMONTH_TO_DATE(base.ProjectMonth) <= '06/01/2011' THEN feb.USDactualamount ELSE 0.0 END)) + (SUM(CASE WHEN RPD.PROJECTMONTH_TO_DATE(base.ProjectMonth) > '06/01/2011' then feb.forecastusd else 0.0 end))) - ((SUM(COALESCE((feb.REVISEDPLANUSD),0)))) AS Variance, 
             CASE WHEN (SUM(COALESCE((feb.REVISEDPLANUSD),0))) = 0 THEN NULL ELSE ((((((SUM(CASE WHEN RPD.PROJECTMONTH_TO_DATE(base.ProjectMonth) <= '06/01/2011' THEN feb.USDactualamount else 0.0 end)) + (SUM(CASE WHEN RPD.PROJECTMONTH_TO_DATE(projectmonth) > '06/01/2011' then feb.forecastusd else 0.0 end)))) - (SUM(COALESCE((feb.REVISEDPLANUSD),0)))) / (SUM(COALESCE((feb.REVISEDPLANUSD),0)))) * 100) END AS Variance_Percentage, 
             pd.ProjectAux1, 
             pd.ProjectComments, 
             pd.VersionType, 
             MAX(base.ModifiedDate) AS ModifiedDate 
      FROM rpd.ProjectDetail pd  INNER JOIN rpd.FundSource fs ON pd.FundSourceId = fs.FundSourceId  
                                 INNER JOIN rpd.Baseline base ON pd.ProjectId = base.ProjectId  
                                 INNER JOIN rpd.FundEntityBaseline feb ON feb.BaselineId = base.BaselineId  
      GROUP BY pd.ProjectAux1, pd.ProjectId, pd.ProjectName, pd.ProjectComments, pd.VersionType)
WHERE VersionType Like '%Text%' WITH UR

Вот схема из 3 таблиц (FundSource не включен, так как в ней всего ~ 200 строк, и я думаю, что она довольно незначительна)

Схема:

FundEntityBaseline ProjectDetail baseline

Ряды:

  • FundEntityBaseline: 354603
  • Базовая линия: 80208
  • ProjectDetail: 1813

Индексы на ProjectDetail:

  • 1 Индекс для первичного ключа (ProjectId)
  • 1 Индекс для внешнего ключа (FundSourceId)
  • 1 Индекс для столбцов SELECT / GROUP BY, содержащих столбцы (ProjectAux1, ProjectId, ProjectName, ProjectComments, VersionType)
  • 1 Индекс с (VersionType, ProjectName)

Индексы по базовой линии:

  • 1 Индекс для первичного ключа (BaselineId)
  • 1 Индекс для внешнего ключа (ProjectId)
  • 1 Индекс с (ProjectTeamId, ProjectMonth)
  • 1 Индекс только с ProjectMonth

Индексы на FundEntityBaseline

  • 1 Индекс для первичного ключа (FundEntityBaselineId)
  • 1 Индекс для внешнего ключа (BaselineId)

Последний план доступа: Access Plan

Ответы [ 2 ]

0 голосов
/ 26 июля 2011

Поместите (= пересоздайте) ваши индексы в табличное пространство с размером страницы 32 КБ - если это еще не настроено.

0 голосов
/ 26 июля 2011

Переместите предложение where (WHERE VersionType Like '% Text%) в строку вверх, чтобы оно было во внутренней инструкции SQL. Теперь ваш запрос сначала выполнит все возможные объединения, а затем отфильтрует этот полный набор с помощью предложения where.

Так что ваше утверждение будет похоже на

WHERE pd.VersionType Like '%Text%'
GROUP BY .....
...