Pregunta

Estoy trabajando en un procedimiento almacenado de búsqueda para nuestros foros existentes.

He escrito el siguiente código que utiliza índices de texto completo de SQL estándar, sin embargo, estoy seguro de que hay una mejor manera de hacerlo y me gustaría un punto en la dirección correcta.

Para proporcionar información sobre cómo debe funcionar, la página tiene un cuadro de texto de búsqueda que, al hacer clic, buscará los títulos de los hilos, las descripciones de los hilos y el texto de la publicación, y debería devolver los resultados con el título primero, luego las descripciones y luego publicar los datos. .

A continuación se encuentra lo que he escrito hasta ahora, que funciona pero no es elegante ni tan rápido como me gustaría. Para dar un ejemplo de rendimiento con hilos de 20K y mensajes de 80K, se tarda unos 12 segundos en buscar 5 palabras al azar.

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

Sé que es un poco largo aliento, pero solo se agradecería un empujón en la dirección correcta.

En caso de que ayude, el 80% del tiempo de consulta se consume cuando se buscan publicaciones y, de acuerdo con el plan de consultas, se gasta en " Análisis de índice agrupado " en la tabla de mensajes. No puedo ver de todos modos alrededor de esto.

Gracias

Gavin

¿Fue útil?

Solución

Realmente tendría que ver un plan explicativo para saber dónde estaban las partes lentas, ya que no veo nada particularmente desagradable en su código. En primer lugar, asegúrese de que todos sus índices estén en buen estado, se estén utilizando, las estadísticas estén actualizadas, etc.

Otra idea sería hacer primero la búsqueda en el título del hilo, luego usar los resultados para eliminar las búsquedas en la descripción del hilo y publicar el texto. Del mismo modo, utilice los resultados de la búsqueda de descripción de hilo para eliminar la búsqueda de texto posterior.

La idea básica aquí es que si encuentra las palabras clave en el título del hilo, ¿por qué molestarse en buscar la descripción y las publicaciones? Me doy cuenta de que esto puede no funcionar dependiendo de cómo presente los resultados de la búsqueda al usuario, y puede que no suponga una gran diferencia, pero es algo en lo que pensar.

Otros consejos

80k registros no es mucho. Recomiendo no insertar los datos resultantes en su tabla temporal, y en su lugar, solo insertar los ID y luego unirse a esa tabla después. Esto se guardará al escribir en la tabla temporal, ya que puede almacenar 10000 ints, en lugar de 10000 publicaciones completas (de las cuales descarta todas las páginas excepto una). Esto también puede reducir la cantidad de tiempo empleado en escanear publicaciones.

Parece que necesitarías dos tablas temporales, una para subprocesos y otra para publicaciones. Los unirías en la selección final.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top