我正在为现有论坛开发搜索存储过程。

我编写了以下使用标准SQL全文索引的代码,但是我确信有更好的方法可以做到这一点,并希望在正确的方向上找到一个点。

要提供一些有关它如何工作的信息,该页面有一个搜索文本框,点击后将搜索主题标题,帖子描述和帖子文本,并应首先返回标题匹配的结果,然后描述然后发布数据。

以下是我到目前为止所写的内容,但它并不优雅,也不像我想的那样快。举一个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%的查询时间。在帖子表上。我无论如何都无法看到这一点。

由于

加文

有帮助吗?

解决方案

我真的必须看一个解释计划才能知道缓慢的部分在哪里,因为我没有在你的代码中看到任何特别讨厌的东西。第一件事 - 确保所有索引都处于良好状态,正在使用它们,统计数据是最新的等等。

另一个想法是首先在线程标题上进行搜索,然后使用其中的结果来修剪线程描述和发布文本的搜索。同样,使用线程描述搜索的结果来修剪帖子文本搜索。

这里的基本想法是,如果您在主题标题中找到关键字,为什么还要费心搜索说明和帖子?我意识到这可能不起作用,这取决于你如何向用户呈现搜索结果,它可能没有太大的区别,但它是值得思考的。

其他提示

80k的记录并不是那么多。我建议不要将结果数据插入临时表,而只是插入ID,然后再加入该表。这将节省写入临时表,因为您可以存储10000个整数,而不是10000个完整帖子(其中您丢弃除了一页之外的所有帖子)。这也可以减少扫描帖子所花费的时间。

看起来你需要两个临时表,一个用于线程,一个用于帖子。你可以在最终的选择中将它们结合起来。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top