0

SQL Server 2012 データベースから実行されている非常に大規模な Web フォーラム アプリケーション (2001 年以降約 2,000 万件の投稿) があります。データファイルのサイズは約 40GB です。

適切なフィールドのテーブルにインデックスを追加しましたが、このクエリ (各フォーラムの投稿の日付範囲を明らかにする) の実行には約 40 分かかります。

SELECT
    T2.ForumId,
    Forums.Title,
    T2.ForumThreads,
    T2.ForumPosts,
    T2.ForumStart,
    T2.ForumStop

FROM
    Forums
    INNER JOIN (

    SELECT
        Min(ThreadStart) As ForumStart,
        Max(ThreadStop) As ForumStop,
        Count(*) As ForumThreads,
        Sum(ThreadPosts) As ForumPosts,
        Threads.ForumId
    FROM
        Threads
        INNER JOIN (

            SELECT
                Min(Posts.DateTime) As ThreadStart,
                Max(Posts.DateTime) As ThreadStop,
                Count(*) As ThreadPosts,
                Posts.ThreadId
            FROM
                Posts
            GROUP BY
                Posts.ThreadId

        ) As P2 ON Threads.ThreadId = P2.ThreadId

    GROUP BY
        Threads.ForumId

) AS T2 ON T2.ForumId = Forums.ForumId

どうすれば高速化できますか?

アップデート:

これは、右から左への推定実行計画です。

[Path 1]

Clustered Index Scan (Clustered) [Posts].[PK_Posts], Cost: 98%
Hash Match (Partial Aggregate), Cost: 2%
Parallelism (Repartition Streams), Cost: 0%
Hash Match (Aggregate), Cost 0%
Compute Scalar, Cost: 0%
Bitmap (Bitmap Create), Cost: 0%

[Path 2]

Index Scan (NonClustered) [Threads].[IX_ForumId], Cost: 0%
Parallelism (Repartition Streams), Cost: 0%

[Path 1 and 2 converge into Path 3]

Hash Match (Inner Join), Cost: 0%
Hash Match (Partial Agregate), Cost: 0%
Parallelism (Repartition Streams), Cost: 0%
Sort, Cost: 0%
Stream Aggregate (Aggregate), Cost: 0%
Compute Scalar, Cost: 0%

[Path 4]
Clustered Index Seek (Clustered) [Forums].[PK_Forums], Cost: 0%

[Path 3 and 4 converge into Path 5]

Nested Loops (Inner Join), Cost: 0%
Paralleism (Gather Streams), Cost: 0%
SELECT, Cost: 0%
4

6 に答える 6

1

インデックスを作成すると機能する場合がありますがSELECT FROM、サブクエリの結果はインデックスに登録されません。それらへの参加はおそらくパフォーマンスを殺している。

buckleyが提案したように、最終的なクエリを実行する前に、中間結果を#tempテーブルに格納し、インデックスを追加してみます。

ただし、アウターSELECTにはスレッド固有の情報は含まれていません。クエリはフォーラムごとに最小/最大の日付を選択しているようです。もしそうなら、あなたはフォーラムによってグループ化された最小/最大/カウントの投稿を取得することができます。

于 2012-06-07T22:23:01.100 に答える
1

これらの 2 つの派生テーブルを #temp テーブルに入れてみましたか? SQL Server はそれらから統計 (単一の列) を取得し、それらにインデックスを配置することもできます。

また、一見したところ、多数の集計があるため、ここではインデックス付きビューが役立ちます。

于 2012-06-07T22:02:09.603 に答える
1

このようなものはどうですか?とにかく、あなたはアイデアを得る...

SELECT f.ForumID,
f.Title,
MIN(p.[DateTime]) as ForumStart,
MAX(p.[DateTime]) as ForumStop,
COUNT(DISTINCT f.ForumID) as ForumPosts,
COUNT(DISTINCT t.ThreadID) as ForumThreads
FROM Forums f
INNER JOIN Threads t
ON f.ForumID = t.ForumID
INNER JOIN Posts p
ON p.ThreadID = p.ThreadID
GROUP BY f.ForumID, f.Title
于 2012-06-07T22:17:20.357 に答える
0

ForumId を Posts テーブルに追加して非正規化すると、Posts テーブルからすべての統計を直接クエリできるようになります。適切なインデックスがあれば、これはおそらくかなりうまくいくでしょう。もちろん、Posts テーブルに挿入するときに ForumId を含めるには、コードを少し変更する必要があります...

于 2012-06-08T21:18:40.700 に答える
0

データベースにさらにいくつかのインデックスを追加したところ、処理速度が大幅に向上しました。実行時間は約 20 秒 (!!) になりました。追加されたインデックスの多くが当て推量 (またはランダムに追加しただけ) であることは認めます。

于 2012-08-25T13:14:01.517 に答える
0

本当に2回集計する必要がありますか? このクエリで同じ結果が得られますか?

SELECT 
T2.ForumId, 
Forums.Title, 
T2.ForumThreads, 
T2.ForumPosts, 
T2.ForumStart, 
T2.ForumStop  
FROM 
    Forums 
INNER JOIN (  
    SELECT
         Min(ThreadStart) As ForumStart,
         Max(ThreadStop) As ForumStop,     
         Count(*) As ForumThreads,     
         Sum(ThreadPosts) As ForumPosts,     
         Threads.ForumId 
    FROM     
        Threads     
    INNER JOIN (          
                SELECT             
                    Posts.DateTime As ThreadStart,             
                    Posts.DateTime As ThreadStop,             
                    Count(*) As ThreadPosts,             
                    Posts.ThreadId         
                FROM             
                    Posts         
                 ) As P2 ON Threads.ThreadId = P2.ThreadId  
    GROUP BY     
        Threads.ForumId  
    ) AS T2 ON T2.ForumId = Forums.ForumId 
于 2012-06-07T22:09:02.980 に答える