2009-03-06 7 views
0

Я работаю над поисковой хранимой процедурой для существующих форумов.SQL Server 2005 Full Text forum Поиск

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

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

Ниже я пишу до сих пор, что работает, но не изящно и не так быстро, как хотелось бы. Чтобы привести пример производительности с потоками 20К и сообщениями на 80 000, для поиска 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 

Я знаю, что он немного длинный, но просто подталкивание в правильном направлении было бы хорошо оценено.

Incase it help 80% времени запроса занято, когда поисковые сообщения и согласно плану запроса расходуются на «Clustered Index Scan» в таблице сообщений. В любом случае, я не вижу этого.

Благодаря

Gavin

ответ

1

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

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

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

+0

Я отредактировал мое сообщение, спасибо за совет, обязательно посмотрит на результаты описания потока. Если он помогает, 80% времени запроса тратится на поисковые сообщения и тратится на «Clustered Index Scan» в таблице сообщений. Я не думаю, что могу избежать этого на столе из 80 тыс. Записей? – Gavin

+0

Нет, вероятно, мало того, что вы можете сделать, чтобы этого избежать. Возможно, вам захочется взглянуть на IOs на это - у вас достаточно памяти на вашем сервере для загрузки этого индекса, или это будут пейджинговые части в и из памяти? –

0

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

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

Смежные вопросы