Avatar billede baatmus Nybegynder
10. november 2004 - 11:03 Der er 11 kommentarer og
1 løsning

FreeText Query med unions - performance

Jeg har en SQL query som driller. Jeg har behov for at gennemsøge en tabel og dens relaterede tabeller for en given tekststreng. Jeg anvender full-text indexing og CONTAINS kommandoen.

I det følgende er main min hoved tabel og rel1-4 mine relaterede tabeller.
Essensen af min query er som følger:

SELECT DISTINCT id, code, name FROM main WHERE id IN
(
SELECT main.id FROM main LEFT JOIN rel1 ON rel1.mainid=main.id
WHERE CONTAINS (rel1.*,'hansen')
UNION
SELECT main.id FROM main LEFT JOIN rel2 ON rel2.mainid=main.id
WHERE CONTAINS (rel2.*,'hansen')
UNION
SELECT main.id FROM main LEFT JOIN rel3 ON rel3.mainid=main.id
WHERE CONTAINS (rel3.*,'hansen')
UNION
SELECT main.id FROM main LEFT JOIN rel4 ON rel4.mainid=main.id
WHERE CONTAINS (rel4.*,'hansen')
)
ORDER BY name

Querien virker godt nok men sjovt nok bliver den meget langsom (14+ sekunder) når jeg tilføler sub selecten i rel4 tabellen. rel4 tabellen har samme karakteristika som rel3 og det gør ingen forskel om jeg bytter om på sub selects eller fjerne dem så fx. kun rel4 sub selecten er tilbage - den er stadig langsom. Men fjerne jeg Rel4 selecten går det straks meget hurtigere (2-3 sek.)
Selve selecten i rel4 tager kun 2 sekunder. Rel4 tabellen ER full-text indexeret og indeholder kun 4 felter hvoraf 2 er indekserede, så det burde ikke give problemer. Der er også oprettet fornuftige indekser på rel4.

Er der nogen der har en ide om, hvad der kan være galt - formodentlig med rel4 tabellens opbygning el. lign.?
Avatar billede veronica Nybegynder
10. november 2004 - 13:54 #1
Er der nogen grund til, at du ikke bruger CONTANSTABLE ?

Mht. performance.. Kunne man forestille sig, at rel4 returnerer rigtigt mange rækker? I så fald, vil jeg tro, det er din UNION kommando, der er bottleneck. Du skal være opmærksom på, at når du bare skriver UNION ( frem for UNION ALL ) så er der ikke ngoen grund til at angive DISTINCT i din øverste select - det betyder blot, at dubletter fjernes to gange.

mvh. Veronica
Avatar billede trer Nybegynder
10. november 2004 - 15:04 #2
Kan hver subselect returnere dubletter?  Hvis ikke, så skift din UNION ud med en UNION ALL. UNION har en implicit sortering for at sikre distincte værdier ud. 

I øvrigt er en EXISTS operator som regel hurtigere end en IN operator.  Det vil give en select a la denne

SELECT DISTINCT id, code, name FROM main m1 WHERE
exists (
SELECT 1 FROM main LEFT JOIN rel1 ON rel1.mainid=main.id
WHERE CONTAINS (rel1.*,'hansen') and main.id = m1.id
UNION ALL
SELECT 1 FROM main LEFT JOIN rel2 ON rel2.mainid=main.id
WHERE CONTAINS (rel2.*,'hansen') and main.id = m1.id
UNION ALL
SELECT 1 FROM main LEFT JOIN rel3 ON rel3.mainid=main.id
WHERE CONTAINS (rel3.*,'hansen') and main.id = m1.id
UNION ALL
SELECT 1 FROM main LEFT JOIN rel4 ON rel4.mainid=main.id
WHERE CONTAINS (rel4.*,'hansen') and main.id = m1.id
)
ORDER BY name


der ud over - du får aldrig top performance når du anvender full text søgning på * i dine relX tabeller...
Avatar billede baatmus Nybegynder
10. november 2004 - 15:08 #3
Hej Veronica!
Er nogen grund til at jeg SKAL bruge CONTAINSTABLE?
Der er ingen nævneværdig forskel på tidsforbruget hvad enten der er ingen eller mange rækker i rel4 queryen. Vi taler om størrelsesordenen 88 rækker.
Avatar billede baatmus Nybegynder
10. november 2004 - 15:10 #4
Hej Trer!
Jeg vil afprøve dine forslag, men mht. * i CONTAINS er der vist ingen vej uden om, når jeg har flere indekserede felter pr. tabel, vel?
Avatar billede trer Nybegynder
10. november 2004 - 15:14 #5
Desværre nok ikke - men min udsagn burde nok også have været på full text generelt og ikke på *.

Mine erfaringer med fulltext er ikke for gode ...
Avatar billede veronica Nybegynder
11. november 2004 - 14:15 #6
Det var ikke for at pådutte dig CONTAINSTABLE - det er bare fordi at jeg bruger CONTAINSTABLE, og så ville jeg høre om det var bedre at bruge CONTAINS.. ?

Jeg ville nok have skrevet din query således:

SELECT DISTINCT main.id, main.code, main.name
WHERE main.id IN
(
SELECT [key] FROM CONTAINSTABLE (rel1, *, 'hansen')
UNION ALL
SELECT [key] FROM CONTAINSTABLE (rel2, *, 'hansen')
UNION ALL
SELECT [key] FROM CONTAINSTABLE (rel3, *, 'hansen')
UNION ALL
SELECT [key] FROM CONTAINSTABLE (rel4, *, 'hansen')
)

.. men det giver nok det samme .. ?
Avatar billede baatmus Nybegynder
11. november 2004 - 23:07 #7
Hej Veronica!
Jeg har prøvet containstable og det ser faktisk ud som om den isoleret set er mere effektiv. Problemet er bare - så vidt jeg kan se - at den returnerer primærnøglen og man kan ikke angive flere kriterier i selve select statementet. Så hvis jeg f.eks. var interesseret i alle hansen'er i postnr 5000, skal jeg lave det som en join med containstable, som returnerer alle hansener i alle postnumre for at finde primærnøglen i hovedtabellen via fremmednøglen i relationstabellen, som ikke retureres af containstable.
Giver det mening?
Avatar billede veronica Nybegynder
12. november 2004 - 18:03 #8
Hej igen,
Ja du kan selvfølgelig også lave det som et join..

SELECT DISTINCT main.id, main.code, main.name
FROM Main,
(
SELECT [key] FROM CONTAINSTABLE (rel1, *, 'hansen')
UNION ALL
SELECT [key] FROM CONTAINSTABLE (rel2, *, 'hansen')
UNION ALL
SELECT [key] FROM CONTAINSTABLE (rel3, *, 'hansen')
UNION ALL
SELECT [key] FROM CONTAINSTABLE (rel4, *, 'hansen')
) as relation
WHERE relation.[key] = main.id

Det er muligvis mere effektivt end IN-operatoren.
/Veronica
Avatar billede baatmus Nybegynder
12. november 2004 - 19:07 #9
Hej Veronica!
Jeg ser problemet med CONTAINSTABLE, fordi
...
SELECT [key] FROM CONTAINSTABLE (rel2, *, 'hansen')
...
ikke er nok. Jeg skal fritekstsøge i 2. relationsniveau og derfor begrænse freetext søgningen til KUN at medtage dem som findes i subrelationen. Eller alternativ kun medtage dem som overholder et kriterie på et andet felt i tabellen som f.eks. et postnr.
Avatar billede veronica Nybegynder
13. november 2004 - 11:02 #10
Så må du jo bare joine CONTAINSTABLE med rel2 tabellen selv inde i din subquery .. ?
Ellers tror jeg ikke helt jeg forstår problemet.

Kunne man i øvrigt forestille sig, at det var dette ekstra kriterie, som var årsagen til, at din query blev sløv ? Det var jo også et forsøg at prøve at sætte et index på dette ekstra kriterie?
Avatar billede baatmus Nybegynder
13. november 2004 - 13:00 #11
Jeg har bare en formodning om at et CONTAINSTABLE() resultat med f.eks. 300.000 rows er tungere at danse med end et CONTAINS() som allerede er reduceret til fx. 3.000 FØR contains() udføres.

Jeg har allerede forsøgt at effektivisere ved at sætte indekser på, men det gør heller ingen målbar forskel.
Avatar billede baatmus Nybegynder
18. august 2010 - 11:58 #12
Der kom ingen løsning på problemet, så jeg tager selv points tilbage
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester