【问题标题】:Running an SQL query faster更快地运行 SQL 查询
【发布时间】:2011-06-04 14:56:48
【问题描述】:
   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

这绝不是一个特别复杂的查询,但是因为数据库已经标准化到一个很好的水平,而且我们正在处理大量数据,所以这个查询对于用户来说可能会很慢。

有没有人有关于如何提高速度的提示?如果我从战略上对数据库的某些部分进行非规范化,这会有所帮助吗?在存储过程中运行它会带来显着的改进吗?

我处理数据的方式在我的代码中是有效的,瓶颈确实是这个查询。

谢谢!

【问题讨论】:

  • 您使用的是什么关系型数据库? MySQL、SQL Server、Postgres?
  • SQL-Server 是它运行的平台。只有v2000,有点垃圾!
  • 此外,查询中的某些格式不会误入歧途。编辑:哦,这样更好。
  • 有两个主要问题 1) Db 未标准化,但您认为它是。 “非规范化”非规范化可能会有所帮助,但规范化它会帮助更多。使用您的数据模型发布一个新问题。 2) 查询格式不正确,外部查询没有定义清晰的结构,子查询可以依赖该结构。 3) 当然 IN 使用工作表,所以将其更改为连接。

标签: sql sql-server-2000 query-optimization normalization relational-database


【解决方案1】:

去规范化你的数据库应该是最后的手段,因为(仅选择一个原因)你不想鼓励去规范化允许的数据不一致。

首先是看能否从查询执行计划中得到一些线索。例如,可能是您的子选择成本过高,最好先在临时表中完成,然后在主查询中加入。

此外,如果您看到大量表扫描,您可以从改进的索引中受益。

如果您还没有这样做,您应该花几分钟时间重新格式化您的查询以提高可读性。令人惊讶的是,在执行此操作时,明显的优化会以多么频繁的频率出现在您身上。

【讨论】:

  • +1 说出了我想说的一切。将其插入查询分析器并查看执行计划。
【解决方案2】:

我会尝试分手

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.urlIDa.ProjectPage 上(帮助GROUP BY

【讨论】:

    【解决方案3】:

    如果您的 dbms 有解释其查询计划的工具,请先使用该工具。 (您的第一个相关子查询可能每行运行一次。)确保 WHERE 子句中引用的每一列都有索引。

    这个子查询——WHERE projectID IN (SELECT projectID FROM tblProjects WHERE userID = 5)——肯定可以从被剪切和实现为视图中受益。然后加入视图。

    将点击流数据视为数据仓库应用程序并不罕见。如果你需要走这条路,我通常会实现一个单独的数据仓库,而不是对设计良好的 OLTP 数据库进行非规范化。

    我怀疑将其作为存储过程运行会对您有所帮助。

    【讨论】:

      【解决方案4】:

      我会尝试删除相关子查询(内部(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,那么应该可以简单地使用触发器来填充一个额外的表,其中左右视图位于不同的行中。

      【讨论】:

        猜你喜欢
        • 2016-02-27
        • 2012-06-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-08
        • 2015-05-22
        • 2015-06-05
        相关资源
        最近更新 更多