MySQL: komplexer Multijoin mit Performance-Problemen

E

eXcuvator

Aktives Mitglied
Thread Starter
Dabei seit
31.05.2007
Beiträge
201
Reaktionspunkte
2
Wer Drupal und dessen Modul Webform kennt hat einen kleinen Vorteil, es ist ein Modul zum freien Eintragen von Formularen und -einträgen. Ich habe sie gewarnt, doch Kunde wollte nicht hören - und nun muss ich versuchen, den Query eines Terminkalenders, welcher auf Webform-Einträgen basiert, zu optimieren - so lässt sich das Ding zur Zeit nicht benutzen.

Table webform_submitted_data
nid (formular-id), sid (eintrag-id) cid (feld-id) no (feld-teil) data (wert)

Folgendes ist mein derzeitiger Query:
Code:
SELECT DISTINCT main.`sid` FROM webform_submissions as main
			INNER JOIN webform_submitted_data as y ON y.no = 2  AND main.sid = y.sid AND y.cid = '1179417776' AND y.data = '2007'
			INNER JOIN webform_submitted_data as d ON main.sid = d.sid AND d.`no` = '1' AND d.`cid` = '1179417776'
			
			INNER JOIN webform_submitted_data as m ON main.sid = d.sid AND m.`no` = '0' AND m.`cid` = '1179417776'
			INNER JOIN webform_submitted_data as x ON main.sid = x.sid AND x.`cid` = '1179417857' AND x.`no` = '1' 
			INNER JOIN webform_submitted_data as z ON main.sid = z.sid AND z.`cid` = '1179417857' AND z.`no` = '0'
			WHERE 
					( 
						( 
							( m.`data` < 11 OR ( m.`data` = 11 AND d.`data` <= 19 ) ) 
							AND 
							( z.`data` > 11 OR ( z.`data` = 11 AND x.`data` >= 19 ) ) 
						) 
						OR 
						( 
							( m.`data` < 11 OR ( m.`data` = 11 AND d.`data` <= 19 ) ) 
							AND 
							( z.`data` > 11 OR ( z.`data` = 11 AND x.`data` >= 19 ) ) 
						) 
						OR 
						( 
							( d.`data` >= 19 AND d.`data` <= 23 AND m.`data` >= 11 AND m.`data` <= 11 ) 
							OR 
							( x.`data` <= 23 AND x.`data` >= 19 AND z.`data` >= 11 AND z.`data` <= 11 ) 
						) 
					)

bei mehreren tausend Einträgen nicht mehr verwaltbar, durch die mehreren Joins ist alles kaputt.

Ich suche nun eine Methode um das ganze zu verkürzen, es dauert viel zu lange.

Was mir ausserhalb von MySQL als Notbremse übrig bliebe, wäre SELECT * FROM webform_submitted_data (3 Sekunden pro Query), und dann via php weiterarbeiten und zu selektieren. Auch schlecht, aber immerhin laufend.

Bessere Vorschläge?

Oder gibt es keinen performanteren Weg, um den MySQL Server zu schützen?



Indizes:
Name Typ Kardinalität Feld
PRIMARY PRIMARY 510000 nid sid cid no
sid INDEX 30000 sid
no INDEX 3 no
 
d select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE d ref sid,no no 4 const 114769 Using where; Using temporary
1 SIMPLE main ref sid sid 4 parador.d.sid 1 Using index
1 SIMPLE y ref sid,no sid 4 parador.main.sid 17 Using where; Distinct
1 SIMPLE x ref sid,no sid 4 parador.y.sid 17 Using where; Distinct
1 SIMPLE z ref sid,no sid 4 parador.main.sid 17 Using where; Distinct
1 SIMPLE m ref no no 4 const 245653 Using where; Distinct
 
Es wird einmal eine Temporäre Tabelle gebildet, aber ich wüsste nicht, wie ich das umgehen soll ...
 
Also ich würde erst einmal versuchen, das "DISTINCT" zu vermeiden, sprich die Query so zu formulieren, dass sie genau die Treffer liefert, die ich brauche.

Dann nachschauen, ob auf allen Relationen auch Indexe gesetzt sind.

Zu guter letzt noch die "OR"s vermeiden und stattdessen "UNION" benutzen.

Viel Glück :)
 
Welche Datenbankengine benutzt du?
 
Falls du mit Engine den Typ meinst, ich nutze MyISAM.

Da die Methode, mit welcher Webform einträge speichert, anscheinend nicht ganz klar ist, hier ein Beispielseintrag (Datum Von, Datum bis, titel)
Titel: Hallo
Datum von: 01.02.1999
Datum bis: 03.04.2000

(formular:) 239, (eintrag:) 13, (feld:), 12345, (Nummer:) 0, (Wert:) Hallo
239, 13, 12346, 0, 02
239, 13, 12346, 1, 01
239, 13, 12346, 2, 1999
239, 13, 12347, 0, 04
239, 13, 12347, 1, 03
239, 13, 12347, 2, 2000


1. DISTINCT leider unumgänglich, da ich sonst nur "13" ganz oft bekommen würde
2. UNION? also SELECT UNION SELECT? Das wären doch zwei Querys, also doppelte Last?
3. Indexe sind gesetzt, so hats mir auch der oben kopierte Explain-Dump zurückgegeben.
 
sicher das auch auf d.sid y.sid und main.sid Indizes bestehen? Die werden ja offenbar ( wg. DISTINCT?) nicht genutzt. Desweiteren stellt sich bei nahezu allen komplexen Abfragen die Frage nach der ausreichenden Dimensionierung des Servers. Das eine oder andere GB RAM kann da Wunder wirken.
 
Beide Tabellen haben Indizes auf sid.

Wir haben das Problem mit einem Workaround gelöst, beim hinzufügen der Datensätze wird das Datum zusammengebaut und die sid in eine eigene Tabelle + Datum gebaut.

Vielen Dank für eure Tips
 
Zurück
Oben Unten