2017-04-22 36 views
2

可以说,我有我的MSSQL 2016(后来Azure的SQL)加入和组多个表

[ForumBoards] 1-n [ForumThreads] 1-n [ForumPosts] n-1 [Users] 

这种关系我们有:50米板,20万个主题,100万发的帖子和50K用户

的目标现在是一个板内

  • 线程数

    • 有ID和名称所有电路板
    • 一板内一些职位
    • 最新张贴板
    • 用户ID和最新帖子

    的名字在我的首秀

    SELECT 
        Boards.Id AS BoardsId, 
        Board.Name AS BoardsName, 
        LP.* 
         ThreadsCount = (SELECT Count(*) FROM ForumBoards AS SubB 
             JOIN ForumThreads AS SubT ON SubB.Id = SubT.BoardId 
             WHERE SubB.Id = Boards.Id AND SubT.BoardId = SubB.Id), 
         PostsCount = (SELECT Count(*) FROM ForumBoards AS SubB 
             JOIN ForumThreads AS SubT ON SubB.Id = SubT.BoardId 
             JOIN ForumPosts AS SubP ON SubT.Id = SubP.ThreadId 
             WHERE SubB.Id = Boards.Id AND SubT.BoardId = SubB.Id AND SubP.ThreadId = SubT.Id) 
    FROM ForumBoards as Boards 
    
    OUTER APPLY(
        SELECT 
        TOP 1 SubP.Id AS LatestPostId, 
         SubP.PostedOn AS LatestPostPostedOn, 
         SubP.ThreadId AS LatestPostThreadId, 
         SubT.Topic AS LatestPostThreadTopic, 
         SubU.Id AS LatestPostUserId, 
         SubU.Username AS LatestPostUsername 
         FROM ForumBoards AS SubB 
          JOIN ForumThreads AS SubT ON SubB.Id = SubT.BoardId 
          JOIN ForumPosts AS SubP ON SubT.Id = SubP.ThreadId 
          JOIN Users AS SubU ON SubP.UserId = SubU.Id 
         WHERE SubB.Id = Boards.Id AND SubT.BoardId = SubB.Id AND SubP.ThreadId = SubT.Id AND SubU.Id = SubP.UserId 
         ORDER BY SubP.PostedOn DESC) AS LP 
    

    它有一个令人难以置信的糟糕表现。

    没有

    WHERE SubB.Id = Boards.Id AND SubT.BoardId = SubB.Id AND SubP.ThreadId = SubT.Id AND SubU.Id = SubP.UserId 
    

    它花费45ms,大约有6秒。

    另一个节目是这样一个

    SELECT 
        B.Id, 
        B.Name as BoardName, 
        Count(*) as ThreadsCount, 
        (SELECT Count(*) 
        FROM 
         ForumBoards Boards, ForumThreads Threads, ForumPosts Posts 
         WHERE Boards.Id = Threads.BoardId AND Threads.Id = Posts.ThreadId AND Boards.Id = B.Id) AS PostsCount 
    
    FROM ForumBoards B, ForumThreads T 
    
    WHERE B.Id = T.BoardId 
    
    GROUP BY B.Id, B.Name 
    

    这是确定的,约172ms - 但没有最新帖子。

    但我认为我在对冲的错误一面。并提示我如何达到我的目标?

  • +0

    你已经创建非聚集索引在连接操作中使用的列(它也与相关查询有关)? – hastrb

    +0

    @AliaksandrBortnik MSSQL query ex plan recommended to create CREATE NONCLUSTERED INDEX IX_ForumThreads_BoardRelation ON [dbo]。[ForumThreads]([BoardId])INCLUDE([Id])'完成了,是的。 – Ben

    +0

    表中的ID是否有聚集索引? – hastrb

    回答

    2

    好吧,这似乎是一个类似于论坛的项目,所以首先要记住的是:您的阅读方式比写在您的数据库上要多。

    避免每次有人显示您的首页时应运行复杂的查询,这不是一个好主意,您只会结束一个slu DB的数据库。

    这种问题在哪里可以通过奇迹触发。

    board增加5个新列:

    • nb_threads
    • nb_posts
    • last_post_id
    • last_user_id
    • last_user_name

    并添加以下触发器:

    • ForumThreads.trgAddThread => 1至母体ForumBoards.nb_threads
    • ForumThreads.trgDeleteThread => -1至母体ForumBoards.nb_threads
    • ForumPosts.trgAddPost => 1至母体ForumBoards.nb_posts,设置将当前post.id转换为last_post_id,将user.id转换为last_user_id并获取user.name以设置last_user_name
    • ForumPosts.trgDeletePost => -1至父代ForumBoards.nb_posts并取回最后一个帖子以更新t他以前的数据

    如果您不能使用触发器(如你在评论解释),这个查询应该做400毫秒下的伎俩:

    SELECT 
        Boards.Id AS BoardsId, 
        Boards.Name AS BoardsName, 
        coalesce(nbThread.ThreadsCount, 0) ThreadsCount, 
        coalesce(LP.nbPost, 0) nbPost, 
        LP.*, 
    FROM ForumBoards AS Boards 
    LEFT JOIN (
        SELECT BoardId, Count(*) ThreadsCount 
        FROM ForumThreads 
        GROUP BY ForumThreads.BoardId 
    ) AS nbThread 
        ON nbThread.BoardId = Boards.Id 
    LEFT JOIN (
        SELECT 
         t.BoardId, 
         t.nbPost, 
         ForumPosts.Id AS LatestPostId, 
         ForumPosts.PostedOn AS LatestPostPostedOn, 
         ForumPosts.ThreadId AS LatestPostThreadId, 
         ForumThreads.Topic AS LatestPostThreadTopic, 
         Users.Id AS LatestPostUserId, 
         Users.Username AS LatestPostUsername 
         FROM (
          select 
           ForumThreads.BoardId, 
           MAX(ForumPosts.Id) Id, 
           Count(*) nbPost 
          from ForumPosts 
          JOIN ForumThreads 
           ON ForumThreads.Id = ForumPosts.ThreadId 
          GROUP BY ForumThreads.BoardId 
         ) AS t 
         INNER JOIN ForumPosts 
          ON t.Id = ForumPosts.Id 
         INNER JOIN ForumThreads 
          ON ForumThreads.Id = ForumPosts.ThreadId 
         INNER JOIN Users 
          ON Users.Id = ForumPosts.UserId   
    ) AS LP 
        ON LP.BoardId = Boards.Id 
    
    +1

    在董事会本身添加最新的帖子相关数据实际上是最好的主意! Upvoted! :) –

    +0

    感谢您的回答,但只有在没有可用的高性能解决方案时才需要触发器。至少有一些触发器需要像A到B的线程移动,隐藏的帖子等等...... – Ben

    +0

    我们不想把BL放到数据库中 – Ben