Cheatah: mySQL: Wieviele Indizes verwendet mySQL pro Tabelle und Abfrage

Beitrag lesen

Hi Michael,

Bei einer Tabelle mit 10000 Einträgen wäre der Primärschlüsselindex ein solcher. Und der ist auch der wahrscheinlichste Kandidat, überhaupt zu existieren.

natürlich, natürlich, natürlich. Wenn man allerdings auf einen Primary Key geht, wird man kaum noch weitere Einschränkungen brauchen, oder? Es purzelt maximal ein Ergebnis raus - ob man dieses verwirft, ist ohne Index sicherlich nicht langsamer als mit einem zweiten, sondern eher sogar schneller. Bei einem zweispaltigen Index entfällt der Table Access By Rowid; aber so ein Index ist in der Praxis eher die Ausnahme.

10% ist schon fast zu schlecht, um den Index überhaupt erst anzulegen.

Kommt auf die Daten an. Gerade wenn Du eine Handvoll verschiedener Typen hast, sind i.d.R. einige dabei, die mehr als 10% beanspruchen.

Unter 10-15% (d. h. 7-10 verschiedene Werte) brauchst Du gar nicht erst anzufangen - da ist der full table scan wirklich besser.

Sag mir das ruhig - ich weiß das ;-) Allerdings rechnen wir zwei beide auch mit etwas größeren Daten- und Abfragemengen, als es bei privaten Sites zu erwarten ist. In dem Bereich habe ich bisher kein DB-Layout gesehen, in dem ein zwei- bis dreispaltiger Index nicht auch dann sinnvoll war, wenn die erste Spalte vielleicht auf 1-20% einschränkte (je nach Wert).

Sämtliche Indexe meiner aktuellen Suchmaschinen-Implementierung projezieren um zwischen 2 und 6 Zehnerpotenzen! _Das_ sind "gute" Indexe. :-)

Ja, stimmt :-)

Aber ein guter query optimizer

Hat das im Subject gennante DBMS einen solchen? MySQL ist rasend schnell, obwohl (bzw. weil) es äußerst simpel aufgebaut ist. Und wie gesagt: Selbst Oracle lässt sich nicht dazu bewegen, mehrere Indizes bei der selben Tabellenabfrage zu verwenden.

vor allem, wenn dasselbe Statement immer wieder ausgeführt werden muß!

Ja. Hierbei treten aber auch Stichworte wie Caching und Precompiling in den Vordergrund; und zu einem guten DB-Layout gehört auch, dass sich der Layouter über die Optimierung Gedanken macht, um dem DBMS Arbeit zu sparen. Schließlich muss dies _jedes_ Statement schnell bearbeiten, nicht nur _dieses_, weil es zufällig gerade öfter aufgerufen wird, da sollte es nicht unter der eigenen Last zusammenbrechen ;-)

"analyze table" ist der Weg dorthin

Bisweilen ist das aber auch hinderlich. Besonders bei stetigen Änderungen kostet dies regelmäßig viel Zeit; und ob, gerade bei der Verwendung von Bind-Variablen, das Ergebnis der Analyse bei unterschiedlichen Aufrufen auch tatsächlich sinnvoll ist, steht ebenfalls in den Sternen. Wir haben übrigens schon bewusst auf Bind-Variablen verzichtet, weil dann der Execution Plan jedes Mal neu berechnet wird... wegen der unterschiedlichen Ergebnisse war das performanter :-)

Würde ich "analyze" implementieren, dann würde ich auf jeden Fall speichern:

Wie oft würdest Du diese Werte aktualisieren? Schon einen Index aktuell zu halten kostet Rechenzeit (und einiges an Speichermanagement). Eine Analyse kann jedoch nur schwerlich inkrementell gemacht werden, da sie auch darauf beruht, gerade detaillierte Daten _nicht_ zu speichern - im (dumm implementierten) Extremfall müsste jeder INSERT und jedes UPDATE zu einer neuen Analyse führen.

Und bei einem Indexzugriff würde ich diese Liste prüfen, um einen Indexzugriff für diese "pathologisch schlechten" Werte zu verhindern.

Wie wäre es mit ANALYZE INDEX? ;-)

Um das ganze nicht zu sehr ausweiten zu lassen: Es gibt viele Möglichkeiten, viele davon hier und dort implementiert, viele nicht. Eine gute Optimierung ist immer hochgradig individuell - besonders hier gilt das (selbstbezügliche) Prinzip "Pauschalisierungen sind falsch und dumm". Was in dem einen Fall ein hervorragender Gedanke ist, kann einem im anderen Fall das System zusammenbrechen lassen, oder zumindest bringt es längst nicht die gleiche Erfolgsrate und ist vermutlich durch ein anderes Vorgehen zu toppen.

Und trotz alledem kenne ich kein DBMS, welches mehrere Indexzugriffe bei einer einzelnen Tabellenabfrage machen würde - meiner Ansicht nach ist das ein recht sicheres Zeichen dafür, dass eine solche Methode doch eher problematisch als hilfreich ist.

Der vor mir beschriebene Fall war auch "konstruiert".

Ja, und im Einzelfall hast Du zweifellos auch recht :-)

Aber ein execution plan optimizer ist KI

Manchmal aber mehr "K" als "I" ;-)

Execution Plan

0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'BAK_CATEGORY'
   2    1     INDEX (RANGE SCAN) OF 'TESTINDEX' (NON-UNIQUE)
Also, der Index wird verwendet.
Ja - für die erste der beiden WHERE-Klauseln. Aber nicht für die zweite. (Wie denn auch? ;-)

Ganz einfach: Die zweite Spalte befindet sich im Range der ersten. "x%" ist ein vollständiger Bereich des Index von A bis B, und darin wird nach allen "y%" der zweiten Spalte gesucht. Anders wäre es natürlich, wenn Du "%y" suchen würdest - soweit ich weiß kann man aber in manchen Systemen (htdig fällt mir spontan ein) auch umgekehrte Indizes einsetzen, die eben exakt dieses erlauben. In Oracle habe ich es noch nie gebraucht; keine Ahnung, ob es das dort gibt.

Klar erkennt Oracle, daß es mit dem zweispaltigen Index wenigstens die erste der beiden Spalten adressieren kann - aber die zweite nicht, weil es dafür einen String-Match über ein concat beider Spaltenwerte machen müßte, und das geht nicht wegen der wildcard am Ende der ersten WHERE-Klausel.

Soweit ich informiert bin, können die Spalten im Index klar voneinander getrennt werden, und zwar ohne Performanceverlust. Zumindest wenn ich nur die beiden indizierten Spalten selektiere, wird der Table Access By Rowid auch weggelassen. Ergo scheint die Prüfung nichts weiter als den Index zu brauchen.

Cheatah