SQL Server 2005 Полнотекстовый форум Поиск - PullRequest
0 голосов
/ 06 марта 2009

Я работаю над поисковой хранимой процедурой для наших существующих форумов.

Я написал следующий код, который использует стандартные полнотекстовые индексы SQL, однако я уверен, что есть лучший способ сделать это и хотел бы указать точку в правильном направлении.

Чтобы дать некоторую информацию о том, как это должно работать, на странице есть 1 текстовое поле поиска, которое при нажатии будет искать заголовки нитей, описания нитей и текст публикации и должно сначала возвращать результаты с совпадениями заголовков, затем описания, затем публиковать данные ,

Ниже то, что я написал до сих пор, работает, но не элегантно и не так быстро, как хотелось бы. Чтобы привести пример производительности с 20K-потоками и 80K-сообщениями, требуется около 12 секунд для поиска 5 случайных слов.

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% времени запроса затрачивается при поиске сообщений и в соответствии с планом запроса тратится на «Сканирование кластерного индекса» в таблице сообщений. Я все равно не вижу вокруг этого.

Спасибо

Gavin

Ответы [ 2 ]

1 голос
/ 06 марта 2009

Мне действительно нужно увидеть план объяснения, чтобы знать, где медленные части, так как я не вижу ничего особенно неприятного в вашем коде. Самое первое - убедитесь, что все ваши индексы в хорошем состоянии, они используются, статистика актуальна и т. Д.

Еще одна идея заключается в том, чтобы сначала выполнить поиск по названию темы, а затем использовать полученные результаты, чтобы обрезать результаты поиска по описанию темы и опубликовать текст. Аналогичным образом, используйте результаты поиска по описанию темы, чтобы обрезать текстовый поиск по сообщению.

Основная идея здесь заключается в том, что если вы найдете ключевые слова в заголовке темы, зачем искать в описании и сообщениях? Я понимаю, что это может не сработать в зависимости от того, как вы представляете результаты поиска пользователю, и это может не иметь большого значения, но об этом стоит подумать.

0 голосов
/ 25 ноября 2009

80k записей не так уж много. Я бы рекомендовал не вставлять полученные данные в вашу временную таблицу, а вместо этого только вставлять идентификаторы, а затем присоединяться к этой таблице. Это сэкономит на записи во временную таблицу, так как вы можете хранить 10000 дюймов вместо 10000 полных сообщений (из которых вы отбрасываете все, кроме одной страницы). Это также может сократить время, затрачиваемое на сканирование сообщений.

Похоже, вам понадобятся две временные таблицы: одна для тем и одна для сообщений. Вы бы объединили их в окончательном выборе.

...