質問

既存のフォーラムの検索ストアドプロシージャに取り組んでいます。

標準のSQLフルテキストインデックスを使用する次のコードを記述しましたが、より良い方法があると確信しており、正しい方向にポイントが必要です。

動作に必要な情報を提供するために、ページには1つの検索テキストボックスがあり、クリックするとスレッドのタイトル、スレッドの説明、投稿テキストが検索され、最初にタイトルが一致する結果が返され、次に説明、次にデータが投稿されます。

以下はこれまでに書いたものですが、動作しますが、エレガントではなく、私が望むほど速くありません。 20Kスレッドと80K投稿のパフォーマンスの例を挙げると、5つのランダムな単語を検索するのに約12秒かかります。

ALTER PROCEDURE [dbo].[SearchForums]
(
    --Input Params
    @SearchText VARCHAR(200),
    @GroupId INT = -1,
    @ClientId INT,
    --Paging Params
    @CurrentPage INT,
    @PageSize INT,           
    @OutTotalRecCount INT OUTPUT
)
AS

--Create Temp Table to Store Query Data
CREATE TABLE #SearchResults
(
    Relevance INT IDENTITY,
    ThreadID INT,
    PostID INT,
    [Description] VARCHAR(2000),
    Author BIGINT
)

--Create and populate table of all GroupID's This search will return from
CREATE TABLE #GroupsToSearch
(
GroupId INT
)
IF @GroupId = -1
    BEGIN
        INSERT INTO #GroupsToSearch
        SELECT GroupID FROM SNetwork_Groups WHERE ClientId = @ClientId
    END
ELSE
    BEGIN
        INSERT INTO #GroupsToSearch
        VALUES(@GroupId)
    END

--Get Thread Titles
INSERT INTO #SearchResults
    SELECT 
        SNetwork_Threads.[ThreadId],
        (SELECT NULL) AS PostId,
        SNetwork_Threads.[Description],
        SNetwork_Threads.[OwnerUserId]
    FROM 
        SNetwork_Threads
        INNER JOIN SNetwork_Groups ON SNetwork_Groups.GroupId = SNetwork_Threads.GroupId        
    WHERE 
        FREETEXT(SNetwork_Threads.[Description], @SearchText) AND
        Snetwork_Threads.GroupID IN (SELECT GroupID FROM #GroupsToSearch) AND
        SNetwork_Groups.ClientId = @ClientId


--Get Thread Descriptions
INSERT INTO #SearchResults
    SELECT 
        SNetwork_Threads.[ThreadId],
        (SELECT NULL) AS PostId,
        SNetwork_Threads.[Description],
        SNetwork_Threads.[OwnerUserId]
    FROM 
        SNetwork_Threads
        INNER JOIN SNetwork_Groups ON SNetwork_Groups.GroupId = SNetwork_Threads.GroupId        
    WHERE 
        FREETEXT(SNetwork_Threads.[Name], @SearchText) AND
        Snetwork_Threads.GroupID IN (SELECT GroupID FROM #GroupsToSearch) AND
        SNetwork_Groups.ClientId = @ClientId


--Get Posts
INSERT INTO #SearchResults
    SELECT 
        SNetwork_Threads.ThreadId,
        SNetwork_Posts.PostId,
        SNetwork_Posts.PostText,
        SNetwork_Posts.[OwnerUserId]
    FROM 
        SNetwork_Posts 
        INNER JOIN SNetwork_Threads ON SNetwork_Threads.ThreadId = SNetwork_Posts.ThreadId
        INNER JOIN SNetwork_Groups ON SNetwork_Groups.GroupId = SNetwork_Threads.GroupId        
    WHERE 
        FREETEXT(SNetwork_Posts.PostText, @SearchText) AND
        Snetwork_Threads.GroupID IN (SELECT GroupID FROM #GroupsToSearch) AND
        SNetwork_Groups.ClientId = @ClientId


--Return Paged Result Sets
SELECT @OutTotalRecCount =  COUNT(*) FROM #SearchResults
SELECT  
    #SearchResults.[ThreadID],
    #SearchResults.[PostID],
    #SearchResults.[Description],
    #SearchResults.[Author]
FROM  
    #SearchResults          
WHERE  
    #SearchResults.[Relevance] >= (@CurrentPage - 1) * @PageSize + 1 AND 
    #SearchResults.[Relevance] <= @CurrentPage*@PageSize
ORDER BY Relevance ASC


--Clean Up
DROP TABLE #SearchResults
DROP TABLE #GroupsToSearch

少し長い曲がりくねっていることは知っていますが、正しい方向に少しだけ動かしていただければ幸いです。

検索投稿の際にクエリ時間の80%が使用され、クエリプランに従って「クラスター化インデックススキャン」に費やされる場合投稿テーブルに。とにかくこの辺りは見えません。

ありがとう

ギャビン

役に立ちましたか?

解決

コードには特に厄介なものは何もないので、遅い部分がどこにあるかを知るために、本当に説明計画を見る必要があります。まず最初に-すべてのインデックスが正常に機能していること、使用されていること、統計が最新であることなどを確認してください。

もう1つのアイデアは、最初にスレッドタイトルで検索を実行し、その結果を使用して、スレッドの説明で検索を削除し、テキストを投稿することです。同様に、スレッド説明検索の結果を使用して、投稿テキスト検索を削除します。

ここでの基本的な考え方は、スレッドのタイトルにキーワードが見つかったら、なぜ説明と投稿をわざわざ検索するのかということです。検索結果をユーザーにどのように表示するかによっては、これが機能しない可能性があり、大きな違いはないかもしれませんが、考えてみてください。

他のヒント

80kレコードはそれほど多くありません。結果のデータを一時テーブルに挿入せず、IDのみを挿入してから、そのテーブルに結合することをお勧めします。これにより、10000の完全な投稿(1ページを除くすべての投稿)の代わりに10000のintを保存できるため、一時テーブルへの書き込みが節約されます。これにより、投稿のスキャンにかかる時間も短縮できます。

スレッド用と投稿用の2つの一時テーブルが必要になるようです。最終選択でそれらを結合します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top