Я работаю над поисковой хранимой процедурой для наших существующих форумов.
Я написал следующий код, который использует стандартные полнотекстовые индексы 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