Question

Je travaille sur une procédure stockée de recherche pour nos forums existants.

J'ai écrit le code suivant qui utilise les index de texte intégral SQL standard, mais je suis sûr qu'il existe un meilleur moyen de le faire et souhaite un point dans la bonne direction.

Pour donner quelques informations sur son fonctionnement, la page comporte une zone de texte de recherche qui, une fois cliquée, permet de rechercher les titres de fil, les descriptions de fil et le texte du post et doit renvoyer les résultats avec les titres correspondants, puis les descriptions, puis les données. .

Ci-dessous, ce que j’ai écrit jusqu’à présent, qui fonctionne, mais n’est pas élégant ni aussi rapide que je le voudrais. Pour donner un exemple de performances avec 20K threads et 80K posts, il faut environ 12 secondes pour rechercher 5 mots aléatoires.

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

Je sais que c'est un peu long, mais un petit coup de pouce dans la bonne direction serait bien apprécié.

Cela aide 80% du temps de la requête est pris en charge lorsque la recherche est publiée et que, selon le plan de requête, celle-ci est utilisée pour "Analyser les index en cluster". sur la table des messages. Je ne vois pas quand même autour de ça.

Merci

Gavin

Était-ce utile?

La solution

Je devrais vraiment voir un plan explicatif pour savoir où se trouvaient les parties lentes, car je ne vois rien de particulièrement méchant dans votre code. Tout d’abord, assurez-vous que tous vos index sont en bon état, qu’ils sont utilisés, que les statistiques sont à jour, etc.

Une autre idée serait d’effectuer d’abord la recherche sur le titre du fil de discussion, puis d’en utiliser les résultats pour ajuster la recherche à la description du fil de discussion et au texte du message. De même, utilisez les résultats de la recherche de description de fil pour élaguer la recherche de texte.

L’idée de base ici est que si vous trouvez les mots-clés dans le titre du fil de discussion, pourquoi chercher dans la description et les messages? Je sais que cela peut ne pas fonctionner en fonction de la manière dont vous présentez les résultats de la recherche à l'utilisateur. Cela ne fera peut-être pas une grande différence, mais c'est quelque chose à penser.

Autres conseils

80 000 enregistrements, ce n’est pas beaucoup. Je vous recommande de ne pas insérer les données résultantes dans votre table temporaire, mais seulement d'insérer les ID, puis de les joindre ensuite à cette table. Cela vous évitera d'écrire dans la table temporaire, car vous pourrez stocker 10000 ints au lieu de 10000 posts complets (dont vous écarterez toutes les pages sauf une). Cela pourrait également réduire le temps consacré à l'analyse des publications.

Il semble que vous auriez besoin de deux tables temporaires, une pour les discussions et une pour les publications. Vous les feriez dans la sélection finale.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top