2017-04-22 110 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