Michael Schröpl: temporäre Tabellen

Beitrag lesen

Hi Andreas,

Das Problem ist, das das ganze bei größeren
Sortiervorgängen unglaublich langsam wird.

dann vermeide sie. Sortiere erst, nachdem Deine
Treffermenge einige hundert Zeilen nicht übersteigt.
Mehr willst Du ohnehin nicht ausliefern.

Daher hatte ich mir überlegt, ich schreibe das
Ergebnis, welches ich mit der FULLTEXT-Suche
gefunden habe in eine temporäre Tabelle mit
begrenzter Datensatz-Anzahl.

Welche Cache-Hit-Rate erwartest Du?
Ich würde etwas im einstelligen Prozentbereich
erwarten, und dafür lohnt sich ein Cache nicht.

Jetzt stellt sich die Frage welches Tabellenformat
ich hierfür verwende. Das beste sollen wohl HEAP-
Tabellen sein, da die direkt im Arbsitspeicher
geladen werden, udn daher extrem schnell sein
sollen.

Im Prinzip hast Du Recht: Wenn Du einen Cache halten
willst, dann wäre in bestimmten Fällen ein Hash, wie
der Tabellentreiber HEAP ihn realisiert, eine gute
Idee. Aber hauptsächlich dann, wenn Du später wieder
auf diesen Hash über eine Indexstruktur zugreifen
willst - ist das bei Dir der Fall?

Und für diesen Indexzugriff zahlst Du einen Preis:
Der Index will erst einmal aufgebaut werden. Bei HEAP
geschieht das offenbar implizit - dadurch wird _dies_
aber um kein bißchen schneller.
Der Aufwand zum Sortieren, den Du kennst und fürchtest,
ist beim Aufbau des HEAP natürlich ebenfalls notwendig,
denn das Ergebnis dieser Sortierung ist das Adressie-
rungssystem für die Einträge des HEAP.

Dieses System wäre also sinnvoll, wenn Du
a) sehr oft auf das Ergebnis zugreifen und
b) dabei immer kleine Teilmengen heraussuchen willst,
   die Du über kleine Mengen von Spaltenwerten angibst.
Dieses Szenario liegt bei Deiner Suche m. E. nicht vor.

  1. Frage ist, welche Daten alle in der temporären
    Tabelle stehen müssen. Am besten schreibt man doch
    alle gefunden Daten in die temporäre Tabelle, um
    dei Datenn direktsortert ausgeben zu können, oder
    sollte man nur die IDs in die Tabelle schreiben und
    auf die "feste" Tabelle joinen?

Hast Du überhaupt die Wahl - wird immer exakt derselbe
JOIN durchgeführt werden? (In meinem Szenario ist das
nicht der Fall ...)

Wenn Du die Tabelle als Cache haben willst, dann
willst Du sehr oft darauf zugreifen.
Willst Du den anschließenden (und wahrscheinlich
ebenfalls teuren) JOIN ebenfalls sehr oft durchführen?

Ein Cache versucht, CPU-Last durch den Einsatz von
Speicher einzusparen.
Das ist nicht der Moment, um am Speicher zu sparen. ;-)

  1. welchen Namen verwende ich für die temporäere
    Tabelle? So wie ich das verstanden habe, sind die
    Temporären Tabellen, so lange existent, für alle
    Clients "gültig".

Nein - nur für Deinen Task.
Deshalb stellt sich Deine Frage gar nicht.

Das heißt wenn cihd ei Tabelle "temp_table" nenne,
kann es bei gleicheitigen Zugriffen auf das Script
welches die temp-Tabelle erzeugt zu Konflikten
kommen.

Richtig. Genau das wird passieren, wenn Du nicht-
temporäre Tabellen verwenden willst, um das Ergebnis
für weitere Zugriffe zu speichern.
Du müßtest Dir die Namen der Tabellen unique generieren
und eine Tabelle mit der Liste aller Tabellen speichern
... oder alternativ den Namen der temporären Tabelle
als zusätzliche Spalte in eine Supertabelle aufnehmen,
aus der Du mit diesem Namen alle Werte der Teil-Tabelle
herausfiltern kannst ...
Dynamisch viele Tabellen können schrecklich werden.

Andererseits hat die Verteilung Deiner Daten auf meh-
rere Tabellen durchaus ihren Reiz.
Wenn Du das aber mal konsequent weiter denkst, könntest
Du auf die Idee kommen, bereits bei der Speicherung
der Postings mehrere Tabellen zu verwenden - so, wie
die bisherige Self-Suche mehrere Indexdateien nutzt.
Wenn Du dann chronologisch rückwärts die Treffer bis
zu einem bestimmten Limit aufsammelst, mußt Du wahr-
scheinlich nur bei sehr guten Suchbegriffen wirklich
alle Tabellen durchsuchen - bei schlechten reicht die
allererste ... Du hast also je nach Suchbegriffen ent-
weder viele schnelle oder nur eine langsame Query,
letztere aber auf einer Teilmenge aller Daten ...

  1. Mir geht es vor allem auch um ORDER BY, und das
    kann HEAP nicht, oder?

Tabellentreiber sollten für die konkrete Syntax der
DML-Statements eigentlich transparent sein. Wie der
Tabellentreiber ein ORDER BY realisiert, das laß mal
seine Sache sein. Und wenn Du genau nach demjenigen
Kriterium sortierst, welches der Schlüssel seines
Hash-Baums ist, dann kann das SELECT vielleicht ein-
fach den bereits sortiert vorliegenden Indexbaum
ablaufen ...

Das kann aber immer noch sehr langsam sein!
Indexzugriffe macht man, um kleine Teilmengen aus
einer großen Gesamtmenge zu extrahieren - nicht, um
eine große Menge damit zu sortieren.
Faustregel: Ein Indexzugriff kostet Faktor 7 (!) mehr
als ein full table scan. Wenn Dein Index also 15% der
vorhandenen Zeilen zurückliefert, hast Du gerade den
break-even.

Sie können nicht nach dem nächsten Eintrag in der

Reihenfolge suchen (also den Index benutzen, um ein
ORDER BY zu machen).

Ah - dann geht das, was ich im vorherigen Absatz be-
schrieben habe, genau bei HEAP nicht performant.
(Natürlich geht ORDER BY, aber Du verlierst dabei die
positiven Eigenschaften des HEAP.)

SELECT id,topic,title,name,time
FROM selfarchiv
WHERE
MATCH (topic,title,name,body) AGAINST ('Datenbank') AND
MATCH (topic,title,name,body) AGAINST ('MySQL')
LIMIT 0, 100;
Das funktioniert sehr schnell, wenn das ganze
erstmal im Cache ist.

Allerdings sind sowohl "MySQL" als auch "Datenbank"
keine "guten" Suchbegriffe - vor allem der zweite ist
viel zu häufig.
In diesem extremen Fall würde ich "Datenbank" auf die
Schwarze Liste setzen, den MATCH nur über mySQL machen
und "Datenbank" via normalen WHERE (LIKE) prüfen.
Wenn die Häufigkeit beider Suchbegriffe sich um mehr
als eine Zehnerpotenz unterscheidet, kann diese Methode
besser sein.
Der Trick besteht natürlich darin, aus Deinen Daten
eine wirklich gute Schwarze Liste zu berechnen ...
daran habe ich eine ganze Weile gesessen.

SELECT id,topic,title,name,time
FROM selfarchiv
WHERE
MATCH (topic,title,name,body) AGAINST ('Datenbank') AND
MATCH (topic,title,name,body) AGAINST ('MySQL')
ORDER BY time DESC
LIMIT 0, 100;

das dauert immer tierisch lange, egal was ich mache.

Ja - Du sortierst viele tausend Treffer und wirfst
danach fast alle wieder weg.

Daher hatte ich mir das ungefähr so überlegt:
CREATE TEMPORARY temp_tabelle  (
INSERT INTO temp_tabelle (id,topic,title,name,time)

Das kannst Du sogar zu _einem_ Befehl zusammensetzen.

SELECT id,topic,title,name,time
FROM temp_tabelle
ORDER BY time DESC;

Genau so mache ich das in meiner Anwendung.
(Ich habe allerdings noch mehr Filterschritte - einer
davon ist ein JOIN gegen eine Entitlement-Tabelle.)

So hatte ich mir das in etwas gedacht.

Mach es einfach!

Oder wäre es besser die unsortierten Daten direkt
auszulesen, ohne Temporäre Tabelle und ORDER BY,
das ganze in einen Array schreiben und den
sortieren?

Das kommt auf Deine Sortierfunktion an. Es ist auf
jeden Fall eine Möglichkeit, die Du prüfen solltest.

Mit einer guten Sortier-Funktion, die nicht die Zeilen
verschiebt, sondern nur Verweise darauf, und die
logarithmisch schnell arbeitet, solltest Du einem
ORDER BY in nichts nachstehen.

Ich habe in meinem Fall sogar einen JOIN in Perl
realisiert, weil es performanter ging, eine Spalte
meiner Treffer gegen einen Hash zu filtern - es war
halt ein JOIN, bei dem ich aus der zweiten Tabelle
keine Felder übernehmen mußte, aber einige hundert
Werte matchen mußte, zu viele für ein "IN" in einer
WHERE-Klausel.

Was ist von wegen Länge der Temporären Tabelle zu
beachten? Sollte ich das mit einem Limit bschränken,
oder ist es egal wenn da einige 1000 Tabellen drin
stehen

Da stehen immer nur ganz wenige Tabellen - nach dem
Ende Deiner Anwendung räumt mySQL sie wieder weg.

denn nur wenn ich alle Datensätze habe kann ich auch
korrekt sortieren, ohne das evtl. relevante
Ergebnisse unter den Tisch fallen?

Tja, _das_ ist der Knackpunkt an Deiner Anwendung:

Willst Du Performance oder Ergebnisqualität als oberste
Priorität? Beides geht nicht ... und ich finde, daß
die Qualität nicht darunter leidet, wenn Du für eine
schlechte Eingabe des Benutzers ein schlechteres Er-
gebnis und eine Aufforderung zur Verbesserung der
Eingabe zurück lieferst, dies aber sehr schnell tust

  • so schnell, daß sich der Anwender tatsächlich in-
    krementell seine Suche mit try & error zusammenbauen
    kann, selbst wenn das mehrere Aufrufe der Suchmaschine
    kostet.

Viele Grüße
      Michael