Michael Schröpl: & (DBI::) & (mySQL): Performance-Messung (Teil 2)

Beitrag lesen

... also weiter im Text:

Mein Problem ist, daß ich unbedingt den Volltextindex brauche, um die Treffermenge effizient zu berechnen, diese dann anschließend aber nach einem völlig anderen Kriterium sortieren muß, um danach erst mit LIMIT die gewünschte Ausgabemenge zu ermitteln und deshalb für das Sortieren selbst keinen bereits existierenden Index mehr nutzen kann. Vielleicht kannst Du das Pferd umgekehrt aufzäumen. Erst sortieren (sortierten Index verwenden - naja, ein Index mit Timestamp als erste Spalte ist natürlich auch nicht das beste...),

Warum nicht? Der projeziert doch wunderbar?

dann grob limitieren, dann gegen die Suchbegriffe gegenchecken. Ich runzele zwar gerade sehr die Stirn, aber vielleicht bringt Dich ja ein anderer Denkansatz auf einen völlig neuen Weg...

Du hast gerade potentiell die Menge der möglichen Varianten an zu erzeugendem SQL-Code verdoppelt ...

Es gibt tatsächlich Fälle, in denen Deine Alternative deutlich schneller wäre - nämlich sehr schlechte Suchabfragen für sehr kurze Zeiträume. Und ich habe tatsächliche solche Fälle - ich denke aber eher darüber nach, dies durch eine noch feinere Aufteilung der Ta- bellen zu bekämpfen ("this hour" etc.). Es gibt aber auch viele Fälle, in denen das andere Verfahren besser wäre - insbesondere alle Abfragen für große Zeiträume, bei denen ich dann wiederum einen full table scan über eine Million Artikel machen müßte. In diesem Falle hätte Deine Idee alle Nachteile der Self-Suche. Hm ... ich fürchte, das wird in relativ wenigen Fällen gut sein ...

(Geben würde es den nämlich schon ... und es gibt sogar Suchanfragen, die davon profitieren können, nämlich solche ohne Suchbegriff, die dann eben nicht "suchen", sondern nur "filtern", über die vielen anderen CGI-Parameter - es ist halt eine Art "Hybridmaschine".) Btw, gibt es bei MySQL ein Äquivalent zu Oracles Hints?

Das Problem ist, daß fast alle Abfragen zuerst nach dem Suchbegriff filtern müssen (das ist der deutlich beste Filter von allen, der unbedingt von siebenstellig auf höchstens vierstellig reduzieren muß) und danach mit temporären Daten ohne Indexstruktur weiter arbeiten. Und zwei Indexe gleichzeitig benutzen geht nun mal nicht ...

Allerdings kann ich an mehreren Stellen abbrechen: Wenn ich genügend Treffer habe und wenn die CGI-Parameterwerte zur Beschreibung des gewünschten Zeitintervalls bestimmte dieser Tabellen ausschließen. Dafür ist allerdings Programmlogik nötig; das bedeutet mehr Roundtrips und damit mehr Zeit, DB-seitige Analysen usw. Eine Auftrennung in mehrere Statements ist i.d.R. nur dann sinnig, wenn üblicherweise nur das erste verwendet wird, jedes weitere aber die Ausnahme bildet.

Im Prinzip gebe ich Dir recht. Vielleicht mache ich das auch mal.

Voraussetzung wäre, daß ich a) die Informationen über die Trefferzahlen nach jedem Zwischenschritt    nicht brauche (die habe ich nämlich bisher und zeige sie sogar im    Ergebnis an, um dem Anwender zu erklären, was er bei einer kleinen    Änderungen seiner Formularwerte noch alles bekommen könnte) und b) mySQL den JOIN für die beiden ersten Filterstufen performant packt    (das teste ich diese Woche mal). Das GROUP BY läßt sich ja leicht mit hinein pfriemeln, wenn ich schon am Zusammenfassen bin.

Ein ähnliches System habe ich mal mit dem Intermedia Text Package verwendet: Die contains()-Funktion wird erst mit dem Suchbegriff gefüttert; wenn das nichts liefert, mit "Suchbegriff%", dann mit "%Suchbegriff%", dann mit "fuzzy(Suchbegriff)". Der letzte Fall dauert ewig (teilweise über 1-2 Sekunden), war aber gegenüber einer leeren Treffermenge der akzeptablere Vorschlag.

Die bisherige Suche dauert zeitweise über 20-30 Sekunden! (Deshalb schreibe ich ja eine neue ... und deshalb habe ich auch so wenig Er- fahrungsdaten darüber, was die Kunden mit der neuen Suche tun werden.)

Ich gehe davon aus, die vorherige full-table-scan-Lösung bei zehn- facher Datenmenge (die bisher wegen des full-table-scans künstlich klein gehalten werden muß) im Schnitt um Faktor 5-10 zu schlagen.

Ich bin aber immer noch unzufrieden damit, daß die reale Suchdauer nach einem für den Anwender in keinster Weise nachvollziehbaren Schema zwischen einer und fünf Sekunden schwanken kann ... je nach- dem, wie gut ich mit meinen Cache-Tabellen zufällig das Trefferlimit erreiche oder auch nicht. Das ist ein reines Glücksspiel: Mehr Treffer anzuzeigen kann genausogut nichts kosten wie eine Katastrophe sein, je nachdem, wie viele ich bei der "kleineren" Suche weggeworfen habe.

Mit dem "nichts finden" habe ich durchaus auch noch meine Probleme - Deine Anregung für das Hinterhersenden "ähnlicher" Anforderungen sind notiert, wobei ich leider aber "[%]Suchbegriff%" nicht machen kann, das gibt meine bisherige Struktur nicht her. (Dann dürfte ich FULLTEXT nicht mehr bzw. nicht mehr als einzige Infrastruktur verwenden; falls das als Kundenanforderung kommt, wird der SQL-Code-Generator wahr-scheinlich noch etwas flexibler werden müssen ...)

"fuzzy(Suchbegriff)" würde in meinem Fall wenig bringen - die Anwender sind keine DAUs, was ihre Suchbegriffe angeht. Eher würde schon "alias" etwas bringen ... darüber denken wir in der Tat nach. Leider ist die Situation ziemlich kompliziert: Wenn ein Anwender nach "Daimler" sucht, bekommt er durchaus reichlich Treffer, würde aber bei "DaimlerChrysler" viel mehr (und großenteils andere!) bekommen (weil in FULLTEXT eben nur Worte drin sind und erst mySQL 4 etwas Anderes als einen exakten Match darauf machen kann). Wie ich ihm das klar machen soll, weiß ich noch nicht ... vielleicht steigen wir bis dahin ja auf mySQL 4 um ...

Es kommt ziemlich oft vor, daß [...] Ich habe also die "schnellen" Anfragen etwas gebremst, um bei den "langsamen" Abfragen den Super-GAU zu verhindern. Klingt durchdacht. Das besagt leider noch nicht, ob es praxis- tauglich ist - wenn die "schnellen" Anfragen überwiegen, durch dieses Konzept aber langsamer werden, ist es eine Verschlimm- besserung.

Das werde ich sehen, wenn ich reale Logdaten habe - schlimmstenfalls kann ich mein System der vielen Cache-Tabellen sehr leicht abschalten. Ich habe wenig Angst davor, daß der Server durch die Suchmaschine zu stark belastet werden wird - mir geht es vor allem darum, daß die Verwendung der Suchmaschine durch subjektiv schnelle Antworten mit guter Qualität überhaupt attraktiv genug wird (die bisherige ist das definitiv nicht). Der Punkt ist, daß die Ausbremsung der "schnellen" Anfragen noch innerhalb der zumutbaren Antwortzeit liegt und die Be- schleunigung der langsamen diese überhaupt erst in diesen zumutbaren Bereich bringt. Jetzt sind alle Abfragen möglich, ohne daß ein Anwen- der vor der Tastatur einschläft. ;-)

Auch liegen teilweise Informationen über typisches Kundenverhalten vor (die Leute kommen morgens ins Büro und wollen erst mal sehen, was seit gestern nachmittag so alles in "ihrer Welt" passiert ist) - das hat die konkrete Art der Tabellenzerlegung überhaupt erst angeregt. Ich hoffe zuversichtlich, daß diese Zerlegung ein Volltreffer wird.

Ich habe also buchstäblich keine Ahnung, wie viel SQL-Code tatsächlich generiert und ausgeführt wird, bevor ich ihn selbst sehe. (Ich habe allerdings durchaus eine Vorstellung davon, was ein "guter" oder "schlechter" Suchbegriff ist und wie viele Treffer in welchen Tabellen etwa zu erwarten sind ... so, wie in diesem Forum hier "HTML" ein außergewöhnlich schlechter und "fatalsToBrowser" ein außergewöhnlich guter Suchbegriff wäre, gibt es ähnliches auch in meinem Datenbestand.) Wenn Du das auflisten oder patternmäßig erkennen kannst, kannst Du individuell darauf reagieren.

Auflisten - vielleicht, ich werde das später mit Log-Daten aus dem realen Betrieb versuchen.

Pattern - keine Chance. Nimm statt "HTML" und "fatalsToBrowser" beliebige Begriffe der deut- schen Sprache - da ist kein "System" drin. Dazu müßte ich die Begrif- fe "verstehen". (Ich habe eine Stopwortliste für den FULLTEXT-Index, aber noch keine "bad words"-Liste ... immerhin könnte ich mir eine bauen, aus einer Häufigkeitstabelle über meinen Datenvorrat ... dafür habe ich sogar schon ein Programm.)

Ich fange zum Beispiel "www." und ".de" ab, wenn sie in "meiner" Produktsuchmaschine eingegeben werden... seltsamerweise passiert das fast in 50% aller(!) Fälle, bei einem Suchformular ohne Autofokus...

Lustig. Aber so etwas habe ich nicht. Ich muß die Benutzer auch nach "schlechten" Begriffen suchen lassen. Wobei bei mir "schlechte" Begriffe diejenigen sind, die viele Treffer liefern - Begriffe, die gar nichts liefern, sind "prima".

Alles in allem bin ich mit meinem Modell schon ziemlich zufrieden Das sind schlechte Voraussetzungen für eine Optimierung... Du wirst versuchen, an dem Konzept festzuhalten :-)

Woher weißt Du das nur? ;-)

Deine Empfehlung der präventiven Limitierung "auf Verdacht" hat mich immerhin ermutigt, dies ernsthaft in Erwägung zu ziehen - die Ent- scheidung, wenige Prozent an Trefferzahl für eine Beschleunigung aller Anfragen zu opfern, steht bisher noch auf der Kippe. Der Punkt ist, daß es in meinem Falle schlimmer wäre als bei Google, wenn ich einem Anwender einen Treffer "vorenthalte" - es könnte auf genau diesen einen Treffer ankommen.

Du hast mich aber gerade auf eine Idee gebracht: Ich kann erkennen, ob eine solche "präventive" Limitierung zugeschlagen hat oder nicht, und dem Benutzer das im Dialog anzeigen - vorausgesetzt, ich mache eben gerade nicht alles in einem einzigen großen JOIN, sondern wie bisher in mehreren nacheinander geschalteten Filtern! Wenn ich den Benutzer zuverlässig warnen kann, daß er nicht alle mög- lichen Treffer sieht, kann er wenigstens darauf reagieren und seine Anfrage ändern. - Das ist auf jeden Fall einen Versuch wert!

(der zu schlagende Vorgänger macht halt auch einen full table scan ... ;-), brüll Ich wette, seine Suchfunktion hat alle Rekorde gebrochen ;-)))

Und wie - siehe oben. (Da bekommt "der zu schlagende" eine interessante Nebenbedeutung. ;-)

Allerdings war sein Datenuniversum eben auch so klein (wegen des mise- ablen Algorithmus), daß bestimmte Suchanforderungen keinen Sinn mach- ten: Ein "Archiv", das künstlich auf 14 Tage limitiert werden muß, taugt halt nichts, wenn man langfristige Entwicklungen beobachten will.

aber es würde mich später ärgern, wenn ich durch einen Finger- fehler irgendwo einen nennenswerten Faktor liegen lassen würde. Das Tabellenlayout kann ebenfalls von entscheidender Bedeutung sein; gerade wenn ein Index nur bedingt verwendet werden kann. Leider kann ich Dir da nicht im Detail helfen; ich vermute aber, dass solche Dinge wie "erst schmale Spalten, dann breite Spalten" ebenfalls gelten. Über die Selbstorganisation verschiedener Spaltentypen steht aber auch in der Doku einiges interessantes.

"So weit unten" reichen meine Kenntnisse über mySQL bisher nicht - ich habe die Spalten bisher nicht bewußt angeordnet. Danke für den Tip! (Wahrscheinlich bin ich von Oracle einfach zu verwöhnt - dem hätte ich zugetraut, sich um so etwas selbst zu kümmern. ;-)

(... das Forum verkraftet meine Antwort auch nicht in zwei Stücken ...)