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
这绝不是一个特别复杂的查询,但由于数据库被规范化到一个良好的水平,并且我们正在处理大量数据,因此该查询对用户来说可能非常慢。
有没有人有关于如何提高速度的提示?如果我策略性地对数据库的某些部分进行非规范化处理会有帮助吗?在存储过程中运行它会有显着的改进吗?
我处理数据的方式在我的代码中很有效,这个问题的瓶颈确实存在。
谢谢!
答案 0 :(得分:3)
我会尝试分手
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
上(以帮助加入),可能在a.urlID
和a.ProjectPage
上(以帮助GROUP BY
)
答案 1 :(得分:3)
取消规范化您的数据库应该是最后的手段,因为(仅选择一个原因)您不希望鼓励去规范化允许的数据不一致。
首先要看看你是否可以从查询执行计划中获得一些线索。例如,可能是您的子选择花费太多,并且最好先进入临时表,然后在主查询中加入。
此外,如果您看到许多表扫描,您可以从改进的索引中受益。
如果您还没有,则应花几分钟时间重新格式化查询以提高可读性。令人惊讶的是,在这样做的过程中,明显的优化会经常出现在你面前。
答案 2 :(得分:1)
如果您的dbms有一个解释其查询计划的工具,请先使用它。 (您的第一个相关子查询可能每行运行一次。)确保WHERE子句中引用的每个列都有索引。
这个子查询 - WHERE projectID IN(SELECT projectID FROM tblProjects WHERE userID = 5) - 肯定会受益于被剪切并作为视图实现。然后加入视图。
将点击流数据视为数据仓库应用程序并不罕见。如果你需要走这条路,我通常会实现一个单独的数据仓库,而不是对设计良好的OLTP数据库进行非规范化。
我怀疑将它作为存储过程运行会对你有帮助。
答案 3 :(得分:1)
我会尝试删除相关子查询(内部(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,那么应该可以简单地使用一个触发器来填充附加表,例如,在左边视图和右视图中使用不同的行。