de context
ik ben bezig met een zoekmachine en een indexeer-script, die een mysql-database met allemaal soorten informatie op woordjes indexeert en in 2 mysql-opzoektabellen wegschrijft.
tabel search_words: lijst met unieke woorden, hun soundex. bevat rond de 50.000 unieke woorden
tabel search_rel: kruistabel met koppeling naar search_words.word_id en naar bron-tabel, bron-record-id. bevat een kleine 900.000 koppelingen
het zoekscript doet bij elke zoekopdracht eerst een scan op de woorden waar de gebruiker op zoekt, en geeft vervolgens de word_id's van de gevonden woorden terug. (een combinatie van een mysql query en php verwerking - dit stuk is vooralsnog optimaal, < 0.009 seconden). vervolgens doe ik een tweetal queries op de gevonden word_id's.
Query om totaal aantal results te tellen, zodat dit over meerder pagina's verdeeld kan worden:
Query om de eerste 20 results te geven, gesorteerd op aantal gevonden worden en totaalsom van gewicht van woorden:
de vragen
1. de 2 genoemde queries hierboven zijn erg traag, de eerste keer dat ze uitgevoerd worden. pak'em beet tussen de 1 en 9 secondes per zoekopdracht. wat ik bovendien niet snap, is dat hij na de eerste trage keer de queries wel snel zijn, rond de 0.01 en 0.1 seconde. query cache, daar zou je aanvankelijk aan denken maar feit is dat het mysql versie 3.23.49 is en die ondersteunt nog geen query cache (http://dev.mysql.com/doc/refman/4.1/en/query-cache.html).
2. mbv EXPLAIN heb ik gekeken waar de zwaktes zitten. bij de query die het totaal aantal telt, wordt wel een index gebruikt van de word_id's, maar een COUNT() op alle rijen met dezelfde word-id kan het traag maken. enige wat ik kan verzinnen is om, na het indexeren, ook per woord te calculeren hoe vaak deze wordt gebruikt en deze dan weer opslaan in de DB. is er nog een slimmere manier om deze query sneller te krijgen?
3. de 2e query, die maakt volgens EXPLAIN gebruik van een temporary en filesort tabel - snel is anders dus. probleem is dat ik gebruikmaak van GROUP BY op het veld source_id, en dat een index op dat veld weinig zin heeft en mysql een temp-table moet aanmaken. verder is het probleem dat ik wil sorteren op hoe vaak een woord in een bepaalde bron voorkomt, en wat het gewicht van dat woord ten opzichte van die bron is. die wil ik ook weer bundelen en op sorteren, dmv SUM(srel.weight) 'total_words_weights', COUNT(srel.word_id) 'unique_words_found'. aangezien deze kolommen niet eens in de DB bestaan maar berekend worden, kunnen die niet geindexeerd worden en wordt uitgeweken naar filesort.
het enige wat ik kan verzinnen, is door GROUP BY en ORDER BY te laten vallen, in plaats daarvan alles op te vragen en het complete resultaat in php te gaan groeperen, sorteren. echter, m'n result-set kan erg lang worden, zo'n 1000 - 2000 rows per zoekopdracht (sommige woorden komen namelijk in > 1000 verschillende bronnen voor). iemand tips?
ik ben bezig met een zoekmachine en een indexeer-script, die een mysql-database met allemaal soorten informatie op woordjes indexeert en in 2 mysql-opzoektabellen wegschrijft.
tabel search_words: lijst met unieke woorden, hun soundex. bevat rond de 50.000 unieke woorden
tabel search_rel: kruistabel met koppeling naar search_words.word_id en naar bron-tabel, bron-record-id. bevat een kleine 900.000 koppelingen
het zoekscript doet bij elke zoekopdracht eerst een scan op de woorden waar de gebruiker op zoekt, en geeft vervolgens de word_id's van de gevonden woorden terug. (een combinatie van een mysql query en php verwerking - dit stuk is vooralsnog optimaal, < 0.009 seconden). vervolgens doe ik een tweetal queries op de gevonden word_id's.
Query om totaal aantal results te tellen, zodat dit over meerder pagina's verdeeld kan worden:
SQL:
1
2
3
4
| SELECT COUNT(DISTINCT srel.source_id) FROM ws_search_rel srel WHERE srel.word_id IN (word_id1, word_id2, word_id3) |
Query om de eerste 20 results te geven, gesorteerd op aantal gevonden worden en totaalsom van gewicht van woorden:
SQL:
1
2
3
4
5
6
7
| SELECT srel.source_id, srel.source_type, SUM(srel.weight) 'total_words_weights', COUNT(srel.word_id) 'unique_words_found' FROM ws_search_rel srel WHERE srel.word_id IN (word_id1, word_id2, word_id3) GROUP BY srel.source_id ORDER BY unique_words_found DESC, total_words_weights DESC LIMIT 0,20 |
de vragen
1. de 2 genoemde queries hierboven zijn erg traag, de eerste keer dat ze uitgevoerd worden. pak'em beet tussen de 1 en 9 secondes per zoekopdracht. wat ik bovendien niet snap, is dat hij na de eerste trage keer de queries wel snel zijn, rond de 0.01 en 0.1 seconde. query cache, daar zou je aanvankelijk aan denken maar feit is dat het mysql versie 3.23.49 is en die ondersteunt nog geen query cache (http://dev.mysql.com/doc/refman/4.1/en/query-cache.html).
2. mbv EXPLAIN heb ik gekeken waar de zwaktes zitten. bij de query die het totaal aantal telt, wordt wel een index gebruikt van de word_id's, maar een COUNT() op alle rijen met dezelfde word-id kan het traag maken. enige wat ik kan verzinnen is om, na het indexeren, ook per woord te calculeren hoe vaak deze wordt gebruikt en deze dan weer opslaan in de DB. is er nog een slimmere manier om deze query sneller te krijgen?
3. de 2e query, die maakt volgens EXPLAIN gebruik van een temporary en filesort tabel - snel is anders dus. probleem is dat ik gebruikmaak van GROUP BY op het veld source_id, en dat een index op dat veld weinig zin heeft en mysql een temp-table moet aanmaken. verder is het probleem dat ik wil sorteren op hoe vaak een woord in een bepaalde bron voorkomt, en wat het gewicht van dat woord ten opzichte van die bron is. die wil ik ook weer bundelen en op sorteren, dmv SUM(srel.weight) 'total_words_weights', COUNT(srel.word_id) 'unique_words_found'. aangezien deze kolommen niet eens in de DB bestaan maar berekend worden, kunnen die niet geindexeerd worden en wordt uitgeweken naar filesort.
het enige wat ik kan verzinnen, is door GROUP BY en ORDER BY te laten vallen, in plaats daarvan alles op te vragen en het complete resultaat in php te gaan groeperen, sorteren. echter, m'n result-set kan erg lang worden, zo'n 1000 - 2000 rows per zoekopdracht (sommige woorden komen namelijk in > 1000 verschillende bronnen voor). iemand tips?
[ Voor 15% gewijzigd door js303 op 09-05-2006 15:44 ]