2012-01-19 3 views
5

Ho il requisito per cercare diverse tabelle nel mio database SQL Server. E ho bisogno di ordinare i risultati in base a quale tabella si è verificata la corrispondenza.Ottimizza ricerca full-text su più tabelle

L'approccio che ho preso è mostrato di seguito. Tuttavia, questo non sembra molto efficiente in quanto aumenta la quantità di dati.

Qualcuno può suggerire qualche trucco per ottimizzare questo?

-- Full-text query 
DECLARE @FtsQuery nvarchar(100) 
SET @FtsQuery = 'FORMSOF(INFLECTIONAL, detail)' 

-- Maximum characters in description column 
DECLARE @MaxDescription int 
SET @MaxDescription = 250 

SELECT 1 AS RankGroup, FTS.Rank, Id, Title, LEFT([Description], @MaxDescription) AS Description FROM Table1 
    INNER JOIN CONTAINSTABLE(Table1, *, @FtsQuery) AS FTS ON FTS.[KEY] = Table1.Id 
UNION SELECT 2, FTS.Rank, Id, Title, NULL FROM Table2 
    INNER JOIN CONTAINSTABLE(Table2, *, @FtsQuery) AS FTS ON FTS.[KEY] = Table2.Id 
UNION SELECT 3, FTS.Rank, Id, Title, LEFT([Description], @MaxDescription) FROM Table3 
    INNER JOIN CONTAINSTABLE(Table3, *, @FtsQuery) AS FTS ON FTS.[KEY] = Table3.Id 
UNION SELECT 4, FTS.Rank, Id, Title, LEFT([Description], @MaxDescription) FROM Table4 
    INNER JOIN CONTAINSTABLE(Table4, *, @FtsQuery) AS FTS ON FTS.[KEY] = Table4.Id 
UNION SELECT 5, FTS.Rank, Id, Title, LEFT([Description], @MaxDescription) FROM Table5 
    INNER JOIN CONTAINSTABLE(Table5, *, @FtsQuery) AS FTS ON FTS.[KEY] = Table5.Id 
ORDER BY RankGroup, Rank DESC 

Un'idea che ho considerato è quella di creare una vista indicizzata e quindi eseguire la ricerca sulla vista. Ma dal momento che la vista avrebbe bisogno di questi UNION s, è difficile vedere come sarebbe più efficiente.

+0

Una semplice ottimizzazione che è possibile eseguire in sicurezza è sostituire 'UNION' con' UNION ALL'. Per maggiori informazioni: http://stackoverflow.com/questions/49925/what-is-the-difference-between-union-and-union-all – niaher

risposta

7

Questo è un problema difficile, perché CONTAINSTABLE è in grado di cercare solo l'indice FTS di una singola tabella alla volta. La tua soluzione UNION sopra va bene finché la tua performance è accettabile.

Abbiamo affrontato lo stesso problema di dover cercare in modo efficiente molte colonne da più tabelle in una singola query. Ciò che abbiamo fatto è stato aggregare tutti i dati di queste colonne e tabelle in un'unica tabella di sola lettura. La nostra domanda quindi necessaria una sola chiamata CONTAINSTABLE

CONTAINSTABLE(AggregatedTable, AggregatedColumn, @FtsQuery) 

Abbiamo un processo pianificato che viene eseguito ogni 5-10 minuti e in modo incrementale aggrega qualsiasi contenuto modificato dalla nostra tabella di origine nel nostro singolo di sola lettura tabella di contenuti aggregati.

In generale sembra che l'utilizzo di FTS in qualsiasi database e carico utente di dimensioni ragionevoli significhi che si sta sempre lottando con le prestazioni. Se ritieni che, indipendentemente da ciò che fai, non sia possibile ottenere prestazioni accettabili, potrebbe essere necessario investigare su altre tecnologie come Lucene.

+0

Interessante. Che tipo di approccio hai preso per prendere i dati modificati e inserirlo nella tabella aggregata? E quanto tempo impiega normalmente per eseguire quel lavoro pianificato? – mg1075

+1

Utilizziamo un proc memorizzato pianificato dall'agente sql per aggiornare la tabella denormalizzata. I nostri dati di base hanno un timbro datetime su ogni riga che indica quando l'ultima riga è stata toccata (inserita o aggiornata), quindi la usiamo per fare una popolazione incrementale ogni 5 o 10 minuti. Il nostro carico iniziale è durato circa un'ora, ma le popolazioni incrementali impiegano solo 10 o 20 secondi. –

+0

Grazie per l'input. Suppongo che gli unici problemi di preoccupazione siano: (1) il tempo necessario per interrogare le tabelle per determinare i record che si qualificano per un aggiornamento e (2) se ci sono stati tempi di inattività e un aggiornamento che normalmente sarebbero stati eseguiti - e guardato in un record solo molto indietro nel tempo, non è riuscito a funzionare. – mg1075