Выполнение SQL-запроса быстрее - PullRequest
0 голосов
/ 06 января 2011
   SELECT projectID, urlID, COUNT(1) AS totalClicks, projectPage,
   (SELECT COUNT(1)
     FROM   tblStatSessionRoutes, tblStatSessions
     WHERE  tblStatSessionRoutes.statSessionID = tblStatSessions.ID
     AND    tblStatSessions.projectID = tblAdClicks.projectID
     AND    (tblStatSessionRoutes.leftPageID = tblAdClicks.projectPage OR
           tblStatSessionRoutes.rightPageID = tblAdClicks.projectPage)) AS totalViews
   FROM   tblAdClicks
   WHERE  projectID IN (SELECT projectID FROM tblProjects WHERE userID = 5)
   GROUP  BY projectID, urlID, projectPage
   ORDER  BY CASE projectID
          WHEN 170 THEN
           1
          ELSE
           0
      END, projectID

Это ни в коем случае не является особенно сложным запросом, но поскольку база данных нормализована до хорошего уровня, и мы имеем дело со значительным объемом данных, этот запрос может быть довольно медленным для пользователя.

У кого-нибудь есть советы, как улучшить его скорость?Если бы я стратегически денормализовал части базы данных, это помогло бы?Будет ли запуск его в хранимом процессе существенным улучшением?

В моем коде эффективен способ обработки данных, узкое место действительно в этом запросе.

Спасибо!

Ответы [ 4 ]

3 голосов
/ 06 января 2011

Денормализация вашей базы данных должна быть последним средством, поскольку (если выбрать только одну причину) вы не хотите поощрять несоответствия данных, которые допускают денормализация.может получить некоторые подсказки из плана выполнения запроса.Например, может случиться так, что ваши подвыборы стоят слишком дорого, и лучше сначала сделать их во временных таблицах, которые вы затем присоединяетесь в своем основном запросе.

Также, если вы видите многоСканирования, вы можете воспользоваться улучшенными индексами.

Если вы еще этого не сделали, вам следует потратить несколько минут на переформатирование запроса для удобства чтения.Удивительно, как часто очевидная оптимизация выскакивает у вас при этом.

3 голосов
/ 06 января 2011

Я бы попытался разбить это

projectID IN (SELECT projectID FROM tblProjects WHERE userID = 5)

и используйте вместо этого JOIN:

 SELECT 
     projectID, urlID, COUNT(1) AS totalClicks, projectPage,
     (SELECT COUNT(1) ....) AS totalViews
 FROM
     dbo.tblAdClicks a
 INNER JOIN 
     dbo.tblProjects p ON a.ProjectID = p.ProjectID
 WHERE 
     p.UserID = 5
 GROUP BY 
     a.projectID, a.urlID, a.projectPage
 ORDER BY 
     CASE a.projectID
        WHEN 170 THEN 1
        ELSE 0
     END, a.projectID

Не уверен, насколько это поможет - надеюсь, немного поможет!

Кроме этого, я бы проверил, есть ли у вас индексы в соответствующих столбцах, например на a.ProjectID (чтобы помочь с JOIN) и, возможно, на a.urlID и a.ProjectPage (чтобы помочь с GROUP BY)

1 голос
/ 06 января 2011

Я бы попытался удалить коррелированный подзапрос (внутренний (SELECT COUNT(1) ...)). Необходимость объединиться с вашими сессионными маршрутами, где совпадают либо левая страница, либо правая страница, усложняет задачу. Что-то вроде (но я не проверял это):

SELECT tblAdClicks.projectID, tblAdClicks.urlID, COUNT(1) AS totalClicks, tblAdClicks.projectPage,
       SUM(CASE WHEN leftRoute.statSessionID IS NOT NULL OR rightRoute.statSessionID IS NOT NULL THEN 1 ELSE 0 END) AS totalViews
FROM tblAdClicks
     JOIN tblProjects ON tblProjects.projectID = tblAdClicks.projectID
     LEFT JOIN tblStatSessions ON tblStatSessions.projectID = tblAdClicks.projectID
     LEFT JOIN tblStatSessionRoutes leftRoute ON leftRoute.statSessionID = tblStatSessions.ID AND leftRoute.leftPageID = tblAdClicks.projectPage
     LEFT JOIN tblStatSessionRoutes rightRoute ON rightRoute.statSessionID = tblStatSessions.ID AND rightRoute.rightPageID = tblAdClicks.projectPage
WHERE tblProjects.userID = 5
GROUP BY tblAdClicks.projectID, tblAdClicks.urlID, tblAdClicks.projectPage
ORDER BY CASE tblAdClicks.projectID WHEN 170 THEN 1 ELSE 0 END, tblAdClicks.projectID

Если бы мне нужно было добавить несколько таблиц кеша, как я указал, я бы попытался свести два запроса к tblStatSessionRoutes для левой и правой страницы до одного запроса. Если вы знаете, что leftPageID никогда не будет равен rightPageID, можно просто использовать триггер, чтобы заполнить дополнительную таблицу с левым и правым представлениями, например, в отдельных строках.

1 голос
/ 06 января 2011

Если в вашей базе данных есть инструмент, объясняющий план запроса, используйте его в первую очередь.(Ваш первый коррелированный подзапрос может выполняться один раз для каждой строки.) Затем убедитесь, что у каждого столбца, на который есть ссылка в предложении WHERE, есть индекс.

Этот подзапрос - ГДЕ projectID IN (ВЫБЕРИТЕ projectID ИЗ tblProjects WHERE userID = 5) - может, безусловно, выиграть от обрезки и реализации в виде представления.Затем присоединитесь к представлению.

Нет ничего необычного в том, чтобы обрабатывать данные о потоках кликов как приложение хранилища данных.Если вам нужно пойти по этому пути, я обычно реализую отдельное хранилище данных, а не денормализую хорошо спроектированную базу данных OLTP.

Я сомневаюсь, что запуск его в качестве сохраненного процесса поможет вам.

...