Ik denk, ik open ook eens een topic.
Het is als volgt. Ik heb een query die auteurs ophaalt op basis van een keyword. Hij moet onder andere auteurs teruggeven die een titel geschreven hebben die overeenkomt met het keyword, en wel op drie manieren:
* Volledige titel (titel == keyword)
* Gedeeltelijke titel (volledig woord zit in titel)
* Gedeeltelijk woord (gedeelte van woord zit in titel)
Nu had ik dat in eerste instantie met een aantal subqueries opgelost, ongeveer zo:
De reden dat dit in twee subqueries kwam is omdat je dan in de ORDER BY ook dezelfde subqueries mee kunt nemen, om zo te kunnen sorteren op het matchtype - volledige titels komen eerst, gedeeltelijke, volledig woord titels komen tweede, en gedeeltelijk woord in de titels komen als derde (zie de order by-clausule).
Probleem met bovenstaand: de performance is belabberd, 30 seconden op tabellen met ~3000 auteurs en ~6500 boeken, en dat was nog maar met twee voorwaarden (volledige match titel en volledig woord in titel).
Als je de twee voorwaarden in één subquery stopt zijn de performanceproblemen weer opgelost: binnen 50 ms klaar. Waarschijnlijk gaat hij door de OR alle resultaten van de ene met die van de ander vergelijken, waardoor je vele duizenden vergelijkingen krijgt ineens. Subquery:
Effectieve vraag: Is er een methode waarmee je kunt selecteren op zowel volledige, gedeeltelijke (volledig woord) en gedeeltelijke match, waarbij je de manier waarop gematched is terug kunt vinden die ook nog eens performant is?
Ja ik weet, je kunt een externe indexer erbij halen, maar dat doen we liever niet op dit punt - het is een tijdelijke oplossing, in de nabije toekomst gooien we de database weg en vervangen we het met een content repository (oid).
Edit: Hm, het lijkt erop dat het niet zozeer in de verschillende inner queries zit, maar in de OR van de WHERE-clause. Als ik het volgende doe:
dan is de uitvoeringstijd weer 30 seconden. Haal de afn.authorName = @search OR weg, en het is weer naar 50 ms.
Bij bovenstaande query heeft de STATISTICS IO het volgende te zeggen:
de 'PropductCopyrightHouder'-koppeltabel (product <-> auteur) lijkt het zwaar te verduren te hebben. Komt dat door die OR?
Nog vollediger: De vAuthorFullNames is een view die slechts drie kolommen uit de CopyrightHouder tabel haalt en deze samenvoegt als volledige naam. Hier worden geen extra tabellen bijgehaald.
Het is als volgt. Ik heb een query die auteurs ophaalt op basis van een keyword. Hij moet onder andere auteurs teruggeven die een titel geschreven hebben die overeenkomt met het keyword, en wel op drie manieren:
* Volledige titel (titel == keyword)
* Gedeeltelijke titel (volledig woord zit in titel)
* Gedeeltelijk woord (gedeelte van woord zit in titel)
Nu had ik dat in eerste instantie met een aantal subqueries opgelost, ongeveer zo:
SQL:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
| SELECT afn.id ,afn.authorName FROM copyrighthouder cph INNER JOIN vAuthorFullNames afn ON afn.Cph_Id = cph.id WHERE cph.id IN ( SELECT pch.cph_id FROM product prd INNER JOIN productcopyrighthouder pch ON pch.prd_id = prd.id WHERE prd.titel = @search ) OR cph.id IN ( SELECT pch.cph_id FROM product prd INNER JOIN productcopyrighthouder pch ON pch.prd_id = prd.id CONTAINS(prd.titel, @ftsearch) ) ORDER BY CASE WHEN cph.id IN ( SELECT pch.cph_id FROM product prd INNER JOIN productcopyrighthouder pch ON pch.prd_id = prd.id WHERE prd.titel = @search ) THEN 1 WHEN cph.id IN ( SELECT pch.cph_id FROM product prd INNER JOIN productcopyrighthouder pch ON pch.prd_id = prd.id CONTAINS(prd.titel, @ftsearch) ) THEN 2 END |
De reden dat dit in twee subqueries kwam is omdat je dan in de ORDER BY ook dezelfde subqueries mee kunt nemen, om zo te kunnen sorteren op het matchtype - volledige titels komen eerst, gedeeltelijke, volledig woord titels komen tweede, en gedeeltelijk woord in de titels komen als derde (zie de order by-clausule).
Probleem met bovenstaand: de performance is belabberd, 30 seconden op tabellen met ~3000 auteurs en ~6500 boeken, en dat was nog maar met twee voorwaarden (volledige match titel en volledig woord in titel).
Als je de twee voorwaarden in één subquery stopt zijn de performanceproblemen weer opgelost: binnen 50 ms klaar. Waarschijnlijk gaat hij door de OR alle resultaten van de ene met die van de ander vergelijken, waardoor je vele duizenden vergelijkingen krijgt ineens. Subquery:
SQL:
1
2
3
4
5
6
7
8
9
10
| -- bla WHERE cph.id IN ( SELECT pch.cph_id FROM product prd INNER JOIN productcopyrighthouder pch ON pch.prd_id = prd.id WHERE prd.titel = @search OR CONTAINS(prd.titel, @ftsearch) ) -- bla |
Effectieve vraag: Is er een methode waarmee je kunt selecteren op zowel volledige, gedeeltelijke (volledig woord) en gedeeltelijke match, waarbij je de manier waarop gematched is terug kunt vinden die ook nog eens performant is?
Ja ik weet, je kunt een externe indexer erbij halen, maar dat doen we liever niet op dit punt - het is een tijdelijke oplossing, in de nabije toekomst gooien we de database weg en vervangen we het met een content repository (oid).
Edit: Hm, het lijkt erop dat het niet zozeer in de verschillende inner queries zit, maar in de OR van de WHERE-clause. Als ik het volgende doe:
SQL:
1
2
3
4
5
6
7
8
9
10
11
12
| WHERE afn.authorName = @search OR cph.id IN ( SELECT pch.cph_id FROM product prd INNER JOIN productcopyrighthouder pch ON pch.prd_id = prd.id WHERE prd.titel = @search OR CONTAINS(prd.titel, @ftsearch) OR prd.titel LIKE @wildcard ) |
dan is de uitvoeringstijd weer 30 seconden. Haal de afn.authorName = @search OR weg, en het is weer naar 50 ms.
Bij bovenstaande query heeft de STATISTICS IO het volgende te zeggen:
code:
1
2
3
4
5
| Table 'Worktable'. Scan count 34, logical reads 39, physical reads 0, read-ahead reads 0. Table 'CopyrightHouder'. Scan count 6, logical reads 77, physical reads 0, read-ahead reads 0. Table 'Product'. Scan count 9048, logical reads 28131, physical reads 0, read-ahead reads 0. Table 'ProductCopyrightHouder'. Scan count 2934, logical reads 316786, physical reads 0, read-ahead reads 0. Table 'Worktable'. Scan count 8984, logical reads 17976, physical reads 0, read-ahead reads 0. |
de 'PropductCopyrightHouder'-koppeltabel (product <-> auteur) lijkt het zwaar te verduren te hebben. Komt dat door die OR?
Nog vollediger: De vAuthorFullNames is een view die slechts drie kolommen uit de CopyrightHouder tabel haalt en deze samenvoegt als volledige naam. Hier worden geen extra tabellen bijgehaald.
[ Voor 20% gewijzigd door YopY op 01-12-2010 16:22 ]