Performance-Problem bei Website-Suche
    
constantin
    
    
      
    
  - datenbank
- 0 Cheatah- 0 constantin- 0 Cheatah
 
 
- 0 Kalle_B
 nicht angemeldet
 nicht angemeldetHallo zusammen,
meine (selbst zusammengeschraubte) Website-Suche kann Und-Abfragen (z.B. constantin dorit), Nicht-Abfragen (constantin -dorit) und Oder-Abfragen (constantin or dorit). Die Und-Suche funktioniert ganz normal, die nicht-suche ist schon um einiges langsamer und bei der oder-suche steht der Server still und liefert auch nach Minuten kein Ergebnis.
Die Suche involviert drei Tabellen:
w_pages (Tabelle mit den indizierten Seite meiner site)
w_keyword (Suchbegriffe)
w_occ ("Vorkommen"-Tabelle)
w_pages und w_keyword haben als PK eine ID und stehen in einer n:n Beziehung zueinander. Beide sind über ihren PK mit der Vorkommen-Tabelle verknüpft. Die Vorkommen-Tabelle nutzt die beiden Fremdschlüssel ihrerseits als zusammengesetzten PK.
Die Tabellenstruktur und meine Abfragensyntax stimmen, so viel ist sicher. Denn wenn ich die Datensatzanzahl bei der Keyword-Tabelle und bei der Vorkommen-Tabelle zu Testzwecken radikal verkleinere, dann funktioniert auch die Oder-Suche.
Hier die Syntax meiner Oder-Suche:
  
SELECT  
  title,description,url,SUM(v.score) hscore  
FROM  
  w_pages s,w_keyword t,w_occ v, (SELECT s.id FROM  
                                    w_pages s,w_keyword t,w_occ v  
                                  WHERE  
                                    t.keyword LIKE '%constantin%' AND  
                                    v.word_id = t.keyword_id AND  
                                    s.id = v.page_id) a0  
WHERE  
  v.word_id = t.keyword_id AND  
  s.id = v.page_id AND  
  t.keyword like '%dorit%'  OR s.id = a0.id AND  
  s.typ = 'g' AND  
  s.lang = 'd'  
GROUP BY  
  url  
ORDER BY  
  hscore DESC, url ASC  
Limit 0, 100  
An der Server-Konfiguration kann ich nichts ändern, da ich nur ein einfaches Webhosting-Paket ohne eigenen Server habe. Andererseits bin ich sicherlich kein Experte für die Feinheiten bei MySql und vermute, dass sich bei meiner Suche Einiges optimieren lässt.
Könnt Ihr mir Tipps geben, was ich verbessern kann, bzw. wo ich ansetzen sollte?
Vielen Dank,
Constantin
Hi,
Könnt Ihr mir Tipps geben, was ich verbessern kann, bzw. wo ich ansetzen sollte?
eliminiere die "LIKE '%...%'" und mache sowas niemals im Leben wieder. Beschäftige Dich mit MATCH AGAINST.
Cheatah
eliminiere die "LIKE '%...%'" und mache sowas niemals im Leben wieder. Beschäftige Dich mit MATCH AGAINST.
Danke cheatah,
ich habe jetzt mittels
CREATE FULLTEXT INDEX kw_full ON w_keyword (keyword)
eine Volltext-Index auf das Feld keyword gelegt und das LIKE in allen Suchabfragen durch MATCH AGAINST ersetzt.
Ergebnis ist eine (gefühlt) deutliche höhere Geschwindigkeit bei der UND-Abfrage und bei der NOT-Abfrage. Bei der Oder-Abfrage steigt er mir aber immer noch aus.
Hier die neue Syntax der Oder-Abfrage
  
SELECT  
  title,description,url,SUM(v.score) hscore  
FROM  
  w_pages s,w_keyword t,w_occ v, (SELECT s.id FROM  
                                    w_pages s,w_keyword t,w_occ v  
                                  WHERE  
                                    MATCH(t.keyword) AGAINST('constantin') AND  
                                    v.word_id = t.keyword_id AND  
                                    s.id = v.page_id) a0  
WHERE  
  v.word_id = t.keyword_id AND  
  s.id = v.page_id AND  
  MATCH(t.keyword) AGAINST('dorit')  OR s.id = a0.id AND  
  s.typ = 'g'  
AND  
  s.lang = 'd'  
GROUP BY  
  url  
ORDER BY  
  hscore DESC, url ASC  
Limit 0, 100  
Habe ich es so richtig gemacht? Lässt sich noch etwas schrauben, meinst Du?
Hi,
Ergebnis ist eine (gefühlt) deutliche höhere Geschwindigkeit bei der UND-Abfrage und bei der NOT-Abfrage. Bei der Oder-Abfrage steigt er mir aber immer noch aus.
setze vor das Statement ein "EXPLAIN " und führe es in PhpMyAdmin aus. Wie lautet das Ergebnis?
Cheatah
setze vor das Statement ein "EXPLAIN " und führe es in PhpMyAdmin aus. Wie lautet das Ergebnis?
OK, dann bekomme ich folgende Antwort (sorry wenn das hier jetzt nicht sehr schön formatiert ist):
id 	select_type 	table 	type 	possible_keys 	key 	key_len 	ref 	rows 	Extra
1 	PRIMARY 	<derived2> 	ALL 	NULL 	NULL 	NULL 	NULL 	75 	Using temporary; Using filesort
1 	PRIMARY 	s 	ALL 	PRIMARY 	NULL 	NULL 	NULL 	2771 	
1 	PRIMARY 	t 	ALL 	PRIMARY 	NULL 	NULL 	NULL 	2967 	Using where
1 	PRIMARY 	v 	index 	PRIMARY,page_id 	page_id 	12 	NULL 	239993 	Using where; Using index
2 	DERIVED 	s 	index 	PRIMARY 	PRIMARY 	4 	NULL 	2771 	Using index
2 	DERIVED 	t 	fulltext 	PRIMARY,kw_full 	kw_full 	0 	  	1 	Using where
2 	DERIVED 	v 	eq_ref 	PRIMARY,page_id 	PRIMARY 	8 	p_galleries.s.id,p_galleries.t.keyword_id 	1 	Using index
So, die Lösung ist gefunden!
Für die Interessierten: Die Syntax der Oder-Abfrage lautet jetzt wie folgt:
  
SELECT  
                title,description,url,SUM(v.score) hscore  
FROM  
                w_pages s,w_keyword t,w_occ v  
WHERE  
                v.word_id = t.keyword_id AND  
                s.id = v.page_id AND  
                s.typ = 'g' AND  
                (MATCH(t.keyword) AGAINST('dorit')  OR s.id IN (SELECT s.id FROM  
                                            w_pages s,w_keyword t,w_occ v  
                                            WHERE  
                                              MATCH(t.keyword) AGAINST('constantin') AND  
                                              v.word_id = t.keyword_id AND  
                                              s.id = v.page_id) )  
GROUP BY  
                url  
ORDER BY  
                hscore DESC, url ASC  
Limit 0, 100  
Was hat sich geändert? 2 Punkte:
Dementsprechend sieht auch die "EXPLAIN"-Antwort viel besser aus:
id 	select_type 	table 	type 	possible_keys 	key 	key_len 	ref 	rows 	Extra
1 	PRIMARY 	s 	ALL 	PRIMARY 	NULL 	NULL 	NULL 	1386 	Using where; Using temporary; Using filesort
1 	PRIMARY 	v 	ref 	PRIMARY,page_id,word_id 	page_id 	4 	p_galleries.s.id 	61 	Using index
1 	PRIMARY 	t 	eq_ref 	PRIMARY 	PRIMARY 	4 	p_galleries.v.word_id 	1 	Using where
2 	DEPENDENT SUBQUERY 	s 	eq_ref 	PRIMARY 	PRIMARY 	4 	func 	1 	Using index
2 	DEPENDENT SUBQUERY 	t 	fulltext 	PRIMARY,kw_full 	kw_full 	0 	  	1 	Using where
2 	DEPENDENT SUBQUERY 	v 	eq_ref 	PRIMARY,page_id,word_id 	PRIMARY 	8 	func,p_galleries.t.keyword_id 	1 	Using where; Using index
Dennoch: Falls jemand Verbesserungs-Tipps hat, wäre ich nach wie vor dankbar:o)
Grüße,
Constantin
Hallo zusammen,
... die nicht-suche ist schon um einiges langsamer und bei der oder-suche steht der Server still und liefert auch nach Minuten kein Ergebnis.
Auf welchen Feldern hast du einen Key?
Kalle
Auf welchen Feldern hast du einen Key?
Hi Kalle,
ich habe folgende Primary Keys definiert:
tabelle,Feld
w_keyword, keyword_id
w_occ, page_id+word_id (zusammengesetzter Schlüssel)
w_pages,id
Dazu muss ich sagen, dass ich diese Sachen komplett in phpmyadmin gemacht habe.
Gruß,
Constantin