Domanda

Sto lavorando a una procedura di ricerca memorizzata per i nostri forum esistenti.

Ho scritto il seguente codice che utilizza indici full text SQL standard, tuttavia sono sicuro che esiste un modo migliore per farlo e vorrei un punto nella giusta direzione.

Per fornire alcune informazioni su come deve funzionare, la pagina ha 1 casella di testo di ricerca che, una volta cliccata, cercherà i titoli dei thread, le descrizioni dei thread e posterà il testo e dovrebbe restituire prima i risultati con le corrispondenze del titolo, quindi le descrizioni e poi i dati .

Di seguito è quello che ho scritto finora che funziona ma non è elegante o veloce come vorrei. Per dare un esempio di performance con 20K thread e 80K post ci vogliono circa 12 secondi per cercare 5 parole casuali.

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

So che è un po 'lungo, ma solo una spinta nella giusta direzione sarebbe apprezzata.

In caso contrario, l'80% del tempo di query viene occupato quando i post di ricerca e in base al piano di query vengono spesi per "Scansione indice cluster". sulla tabella dei messaggi. Non riesco comunque a vedere questo.

Grazie

Gavin

È stato utile?

Soluzione

Dovrei davvero vedere un piano esplicativo per sapere dove fossero le parti lente, dato che non vedo nulla di particolarmente brutto nel tuo codice. Prima cosa: assicurati che tutti gli indici siano in buone condizioni, vengano utilizzati, le statistiche siano aggiornate, ecc.

Un'altra idea sarebbe quella di fare prima la ricerca sul titolo del thread, quindi utilizzare i risultati da quello per eliminare le ricerche sulla descrizione del thread e pubblicare il testo. Allo stesso modo, utilizzare i risultati della ricerca della descrizione del thread per eliminare la ricerca del testo del post.

L'idea di base qui è che se trovi le parole chiave nel titolo della discussione, perché preoccuparsi di cercare la descrizione e i post? Mi rendo conto che potrebbe non funzionare a seconda di come stai presentando i risultati della ricerca all'utente e potrebbe non fare una differenza enorme, ma è qualcosa a cui pensare.

Altri suggerimenti

80k record non sono poi così tanti. Consiglio di non inserire i dati risultanti nella tabella temporanea e di inserire solo gli ID, quindi di unirsi a quella tabella in seguito. Ciò consentirà di risparmiare sulla scrittura nella tabella temporanea, poiché è possibile memorizzare 10000 ints, anziché 10000 post completi (di cui si eliminano tutti tranne una pagina). Ciò può ridurre anche il tempo dedicato alla scansione dei post.

Sembra che avresti bisogno di due tabelle temporanee, una per i thread e una per i post. Li uniresti nella selezione finale.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top