Logische Verknüpfungen in SQL-Statements

Logische Verknüpfungen in SQL-Statements

am 06.01.2007 20:13:01 von Christian Ratsch

Hallo,

ich bin kein Datenbankprofi, vielleicht ist das ne blöde Frage.

Wenn in einem SQL-Statement Bedingungen mit einem AND verknüpft sind und die
Bedingung vor einem AND nicht erfüllt ist, werden dann trotzdem noch die
Bedingungen danach geprüft?

Beispiel:
a sei 0
....WHERE a=1 AND b=2
Da a nicht 1 ist, wird b noch auf 2 geprüft?

Dann könnte ich ja die Menge der zu durchsuchenden Daten zunächst durch
einfache Verknüpfungen stark einschränken (z.B. WHERE flag = xy), bevor
kompliziertere Bedingungen geprüft werden (z.B. AND string LIKE '%xyz%').

Sollte dies so sein: gibt es ein Tool, mit dem man die Performance von
verschiedenen Formulierungen des selben Statements testen kann?

Vielen Dank für Eure Antworten. Gruß,
Christian

Re: Logische Verknüpfungen in SQL-Statements

am 06.01.2007 21:28:38 von Axel Schwenke

"Christian Ratsch" wrote:

> ich bin kein Datenbankprofi, vielleicht ist das ne blöde Frage.

Ist es nicht.

> Wenn in einem SQL-Statement Bedingungen mit einem AND verknüpft sind und die
> Bedingung vor einem AND nicht erfüllt ist, werden dann trotzdem noch die
> Bedingungen danach geprüft?

Die Reihenfolge der Bedingungen ist irrelevant. Der Optimizer des RDBMS
nimmt sich die Freiheit, deine Bedingungen nach Belieben umzugruppieren
oder umzuformen. Möglichst so, daß er die Frage leichter (= schneller)
beantworten kann.

> Dann könnte ich ja die Menge der zu durchsuchenden Daten zunächst durch
> einfache Verknüpfungen stark einschränken (z.B. WHERE flag = xy), bevor
> kompliziertere Bedingungen geprüft werden (z.B. AND string LIKE '%xyz%').

Was "einfach" und "kompliziert" ist, darüber hat die Datenbank
womöglich andere Ansichten als du. Wenn auf der Spalte flag ein UNIQUE
INDEX liegt, ist "flag = xy" tatsächlich einfach, es kann nämlich nur
höchstens eine Zeile die Bedingung erfüllen und über den Index wird
diese Zeile in logarithmischer Zeit gefunden. Hingegen kann für
"string LIKE '%xyz%'" kein Index verwendet werden, sondern es muß die
gesamte Tabelle Zeile für Zeile durchsucht werden.

Andererseits wird ohne Index auf flag, aber mit einem Volltext-Index
auf string bei "WHERE flag=xy AND MATCH(string) AGAINST('xyz')" die
Suche über den Substring für die Datenbank "einfacher" sein.

> Sollte dies so sein: gibt es ein Tool, mit dem man die Performance von
> verschiedenen Formulierungen des selben Statements testen kann?

EXPLAIN gibt dir eine (allerdings etwas schwer verständliche) Idee
davon, wie der Optimizer deine Frage angeht.


XL

Re: Logische Verknüpfungenin SQL-Statements

am 06.01.2007 21:46:18 von Thomas Rachel

Christian Ratsch wrote:

> Wenn in einem SQL-Statement Bedingungen mit einem AND verknüpft sind
> und die Bedingung vor einem AND nicht erfüllt ist, werden dann
> trotzdem noch die Bedingungen danach geprüft?
>
> Beispiel:
> a sei 0
> ...WHERE a=1 AND b=2
> Da a nicht 1 ist, wird b noch auf 2 geprüft?

Nein. Dafür sorgt der Optimizer. Nicht nur das - es wird sogar geprüft,
welche Bedingung die stärkste Einschränkung darstellt (um es mal so
auszudrücken) und daher die meisten Ergebnisse wegwirft.

> Dann könnte ich ja die Menge der zu durchsuchenden Daten zunächst
> durch einfache Verknüpfungen stark einschränken (z.B. WHERE flag =
> xy), bevor kompliziertere Bedingungen geprüft werden (z.B. AND string
> LIKE '%xyz%').

Ja, das macht auf jeden Fall Sinn, vor allem, da u.U. bei der
flag-Bedingung mit Indices gearbeitet werden kann, während das bei LIKE
'%...%' nicht geht.


> Sollte dies so sein: gibt es ein Tool, mit dem man die Performance von
> verschiedenen Formulierungen des selben Statements testen kann?

Du suchst EXPLAIN. Dieser Befehl wird im Handbuch genau beschrieben.


Thomas
--
Roses are red. Violets are blue. Some poems rhyme. But this one doesn't.

Re: Logische Verknüpfungen in SQL-Statements

am 07.01.2007 12:18:33 von Christian Ratsch

"Axel Schwenke" schrieb im Newsbeitrag
news:mp0pne.v77.ln@xl.homelinux.org...
> "Christian Ratsch" wrote:
>
>> ich bin kein Datenbankprofi, vielleicht ist das ne blöde Frage.
>
> Ist es nicht.
>
>> Wenn in einem SQL-Statement Bedingungen mit einem AND verknüpft sind und
>> die
>> Bedingung vor einem AND nicht erfüllt ist, werden dann trotzdem noch die
>> Bedingungen danach geprüft?
>
> Die Reihenfolge der Bedingungen ist irrelevant. Der Optimizer des RDBMS
> nimmt sich die Freiheit, deine Bedingungen nach Belieben umzugruppieren
> oder umzuformen. Möglichst so, daß er die Frage leichter (= schneller)
> beantworten kann.

Das heißt, ich kann nicht zusätzlich durch eine andere Reihenfolge der
Bedingungen einfgreifen, wenn z.B. aus Sicht des Optimizers beide gleich
schwer/schnell zu beantworten sind, obwohl ich aber weiß, dass viel mehr
Ergebnisse wegfallen, wenn zuerst Bedingung A geprüft wird (weil ich ja
einen Überblick über die Inhalte der Tabelle habe und abschätzen kann, dass
z.B. Bedingung A weit seltener erfüllt wird als B, und daher zuert geprüft
werden sollte)? Mann, was für ein Kettensatz... :)

>> Dann könnte ich ja die Menge der zu durchsuchenden Daten zunächst durch
>> einfache Verknüpfungen stark einschränken (z.B. WHERE flag = xy), bevor
>> kompliziertere Bedingungen geprüft werden (z.B. AND string LIKE '%xyz%').
>
> Was "einfach" und "kompliziert" ist, darüber hat die Datenbank
> womöglich andere Ansichten als du. Wenn auf der Spalte flag ein UNIQUE
> INDEX liegt, ist "flag = xy" tatsächlich einfach, es kann nämlich nur
> höchstens eine Zeile die Bedingung erfüllen und über den Index wird
> diese Zeile in logarithmischer Zeit gefunden. Hingegen kann für
> "string LIKE '%xyz%'" kein Index verwendet werden, sondern es muß die
> gesamte Tabelle Zeile für Zeile durchsucht werden.

In meinem konkreten Fall hätte ich es gerne so, dass zunächst einfache
Bedingungen wie "flag_geloescht = 0", "datum >= NOW()", "typ = 1" usw. die
Ergebnismenge drastisch verkleinern und erst danach auf die übrigen
Ergebnisse eine große Zahl weitere logische Operationen (AND, OR) ausgeführt
werden. Auf keinem Feld ist ein Index, und deshalb drüften aus der Sicht der
Datenbank alle Bedingungen gleichwertig sein, weshalb ich eben gerne manuell
nachhelfen würde.

Eine weitere Frage hätte ich noch zur Optimierung: Wenn ich ein Statement
ohne Limit ausführe, um die Anzahl der Suchergebnisse zu ermitteln, und
danach noch einmal die selbe Abfrage mit Limit mache (um in Webseiten durch
die Ergenbnisse zu blättern), wie kann ich es dann erreichen, dass MySQL das
Ergebnis zwischenspeichert und nicht die ganze Abfrage noch einmal von vorne
abarbeitet? (Damit pro Seitenaufruf nur ein Datenbankaufruf statt zwei
notwendig sind.)

Vielen Dank noch einmal & schöne Grüße
Christian

Re: Logische Verknüpfungenin SQL-Statements

am 07.01.2007 12:51:15 von Thomas Rachel

Christian Ratsch wrote:

> Das heißt, ich kann nicht zusätzlich durch eine andere Reihenfolge
> der Bedingungen einfgreifen, wenn z.B. aus Sicht des Optimizers beide
> gleich schwer/schnell zu beantworten sind, obwohl ich aber weiß, dass
> viel mehr Ergebnisse wegfallen, wenn zuerst Bedingung A geprüft wird
> (weil ich ja einen Überblick über die Inhalte der Tabelle habe und
> abschätzen kann, dass z.B. Bedingung A weit seltener erfüllt wird als
> B, und daher zuert geprüft werden sollte)? Mann, was für ein
> Kettensatz... :)

Im Optimalfall weiß der Optimizer das auch.


> In meinem konkreten Fall hätte ich es gerne so, dass zunächst
> einfache Bedingungen wie "flag_geloescht = 0", "datum >= NOW()", "typ =
> 1" usw. die Ergebnismenge drastisch verkleinern und erst danach auf die
> übrigen Ergebnisse eine große Zahl weitere logische Operationen (AND,
> OR) ausgeführt werden. Auf keinem Feld ist ein Index,

Das ist ganz schlecht. Dann hast Du womöglich noch ganz andere Probleme.
Du solltest den Index nachrüsten...

Ob ohne Index eine solche Bedingung dann von links nach rechts oder wie
auch immer ausgewertet wird, weiß ich nicht - kann aber gut sein, daß
das gar nicht erst spezifiziert ist.


> Eine weitere Frage hätte ich noch zur Optimierung: Wenn ich ein
> Statement ohne Limit ausführe, um die Anzahl der Suchergebnisse zu
> ermitteln, und danach noch einmal die selbe Abfrage mit Limit mache (um
> in Webseiten durch die Ergenbnisse zu blättern), wie kann ich es dann
> erreichen, dass MySQL das Ergebnis zwischenspeichert und nicht die
> ganze Abfrage noch einmal von vorne abarbeitet? (Damit pro Seitenaufruf
> nur ein Datenbankaufruf statt zwei notwendig sind.)

Du könntest eine Abfrage ohne LIMIT machen und dann die Navigation
innerhalb des Ergebnisses selbst vornehmen. Das MySQL-API kennt dazu die
Funktionen mysql_row_seek(), mysql_row_tell() etc.

Ob es die in PHP auch gibt, weiß ich allerdings nicht.


Thomas
--
Jabber-ID: glglgl@amessage.info (keine Email-Adresse!)
Warum Jabber, was ist das und wie geht das?
http://de.wikibooks.org/wiki/Jabber-Kompendium:_Schnelleinst ieg

Re: Logische Verknüpfungen in SQL-Statements

am 07.01.2007 13:09:05 von Axel Schwenke

"Christian Ratsch" wrote:
> "Axel Schwenke" schrieb
>>
>> Die Reihenfolge der Bedingungen ist irrelevant. Der Optimizer des RDBMS
>> nimmt sich die Freiheit, deine Bedingungen nach Belieben umzugruppieren
>> oder umzuformen. Möglichst so, daß er die Frage leichter (= schneller)
>> beantworten kann.
>
> Das heißt, ich kann nicht zusätzlich durch eine andere Reihenfolge der
> Bedingungen einfgreifen, wenn z.B. aus Sicht des Optimizers beide gleich
> schwer/schnell zu beantworten sind, obwohl ich aber weiß, dass viel mehr
> Ergebnisse wegfallen, wenn zuerst Bedingung A geprüft wird (weil ich ja
> einen Überblick über die Inhalte der Tabelle habe und abschätzen kann, dass
> z.B. Bedingung A weit seltener erfüllt wird als B, und daher zuert geprüft
> werden sollte)?

Auch darüber weiß der Optimizer Bescheid. Wenn der Optimizer unter
mehreren Indizes wählen kann, benutzt er den mit der höchsten
Selektivität. Table-Scans sind immer gleich aufwendig, da stellt sich
die Frage gar nicht erst.

Außerdem scheinst du immer nur den Aufwand an CPU-Zeit zu betrachten.
Datenbanken werden aber typischerweise eher durch I/O gebremst. Eine
aktuelle Festplatte braucht ca. 5ms, um einen Sektor anzufahren. Eine
1GHz-CPU kann in diesen 5 Mio Taktzyklen eine Menge machen. Ebenso
kann die CPU Daten im RAM wesentlich schneller duchsuchen, als die
Festplatte Daten liefern kann. Manchmal lohnt sich also ein rechen-
aufwendigerer Weg, wenn der dafür I/O spart.

Das Stichwort heißt "cost based optimizer" und MySQL hat da mit 5.0
im Vergleich zu vorher mächtig nachgelegt.

>> Was "einfach" und "kompliziert" ist, darüber hat die Datenbank
>> womöglich andere Ansichten als du.
....

> In meinem konkreten Fall hätte ich es gerne so, dass zunächst einfache
> Bedingungen wie "flag_geloescht = 0", "datum >= NOW()", "typ = 1" usw. die
> Ergebnismenge drastisch verkleinern und erst danach auf die übrigen
> Ergebnisse eine große Zahl weitere logische Operationen (AND, OR) ausgeführt
> werden. Auf keinem Feld ist ein Index, und deshalb drüften aus der Sicht der
> Datenbank alle Bedingungen gleichwertig sein, weshalb ich eben gerne manuell
> nachhelfen würde.

Wenn du nachhelfen willst, dann spendiere der Datenbank Indizes. MySQL
kann ja z.B. einen Index über mehrere Felder anlegen, so daß ein Index
(datum, typ, flag_gelöscht) alle drei Bedingungen quasi auf einen
Schlag beachtet.

Allerdings sind Indizes ein zweischneidiges Schwert. Sie beschleunigen
Lesezugriffe, machen aber dafür Schreibzugriffe langsamer. Welche
Indizes sinnvoll sind, hängt also wesentlich von der Anwendung ab
(bzw. davon, welche Queries sie auf die Datenbank abschießt).


Manchmal kann man trotzdem noch manuell nachhelfen. Immer wieder gerne
bringe ich dazu folgendes Beispiel: gegeben sei eine Tabelle mit
Punkten in der Ebene, dargestellt durch X- und Y-Koordinaten (x,y).
Wir suchen alle Punkte aus der Tabelle, die sich in einem Kreis mit
Radius 10 Einheiten um (x0, y0) befinden.

1. Ansatz: (naiv)
SELECT ... WHERE SQRT((x-x0)*(x-x0) + (y-y0)*(y-y0)) <= 10;

2. Ansatz: (spart das SQRT())
SELECT ... WHERE ((x-x0)*(x-x0) + (y-y0)*(y-y0)) <= 100;

3. Ansatz: (Vorselektion auf das den Kreis umschließende Quadrat,
kann Index auf x und/oder y nutzen)
SELECT ... WHERE (x BETWEEN x0-10 AND x0+10)
AND (y BETWEEN y0-10 AND y0+10)
AND ((x-x0)*(x-x0) + (y-y0)*(y-y0)) <= 100;


> Eine weitere Frage hätte ich noch zur Optimierung: Wenn ich ein Statement
> ohne Limit ausführe, um die Anzahl der Suchergebnisse zu ermitteln, und
> danach noch einmal die selbe Abfrage mit Limit mache (um in Webseiten durch
> die Ergenbnisse zu blättern), wie kann ich es dann erreichen, dass MySQL das
> Ergebnis zwischenspeichert und nicht die ganze Abfrage noch einmal von vorne
> abarbeitet?

Du sparst die Query ohne Limit und verwendest SQL_CALC_FOUND_ROWS:

http://dev.mysql.com/doc/refman/5.0/en/select.html


XL

Re: Logische Verknüpfungenin SQL-Statements

am 07.01.2007 13:15:43 von Andreas Kretschmer

Andreas
--
q: why do so many people take an instant dislike to mysql?
a: it saves time (oicu in #postgresql)
Explaining the concept of referential integrity to a mysql user is like
explaining condoms to a catholic (Shadda in #postgresql)

Re: Logische Verknüpfungen in SQL-Statements

am 07.01.2007 13:28:03 von Kai Ruhnau

Christian Ratsch wrote:
> "Axel Schwenke" schrieb im Newsbeitrag
> news:mp0pne.v77.ln@xl.homelinux.org...

Das ist zu lang, mach' das mal kürzer.

>> "Christian Ratsch" wrote:
>>> Wenn in einem SQL-Statement Bedingungen mit einem AND verknüpft sind und
>>> die
>>> Bedingung vor einem AND nicht erfüllt ist, werden dann trotzdem noch die
>>> Bedingungen danach geprüft?
>> Die Reihenfolge der Bedingungen ist irrelevant. Der Optimizer des RDBMS
>> nimmt sich die Freiheit, deine Bedingungen nach Belieben umzugruppieren
>> oder umzuformen. Möglichst so, daß er die Frage leichter (= schneller)
>> beantworten kann.
>
> Das heißt, ich kann nicht zusätzlich durch eine andere Reihenfolge der
> Bedingungen einfgreifen, wenn z.B. aus Sicht des Optimizers beide gleich
> schwer/schnell zu beantworten sind, obwohl ich aber weiß, dass viel mehr
> Ergebnisse wegfallen, wenn zuerst Bedingung A geprüft wird (weil ich ja
> einen Überblick über die Inhalte der Tabelle habe und abschätzen kann, dass
> z.B. Bedingung A weit seltener erfüllt wird als B, und daher zuert geprüft
> werden sollte)? Mann, was für ein Kettensatz... :)

Du hast eine falcshe Vorstellung, wie der Vergleich intern abläuft.

> In meinem konkreten Fall hätte ich es gerne so, dass zunächst einfache
> Bedingungen wie "flag_geloescht = 0", "datum >= NOW()", "typ = 1" usw. die
> Ergebnismenge drastisch verkleinern und erst danach auf die übrigen
> Ergebnisse eine große Zahl weitere logische Operationen (AND, OR) ausgeführt
> werden. Auf keinem Feld ist ein Index, und deshalb drüften aus der Sicht der
> Datenbank alle Bedingungen gleichwertig sein, weshalb ich eben gerne manuell
> nachhelfen würde.

Da auf keinem der Felder ein Index liegt, *sind* alle Bedingungen gleich
schwer in folgender Hinsicht: Um die Zeilen herauszufiltern auf die alle
Bedingungen zutreffen, müssen sämtliche Zeilen geladen werden und in
sämtlichen Zeilen die Bedingungen überprüft werden. Das Produkt aus
Zeilen und komplexität der Bedingungen ändert sich nicht.

Ich denke, so wie du es schreibst, gehst du davon aus, dass zunächst
alle Zeilen geladen werden, dann eine erste Bedingung überprüft wird und
ein Zwischenergebnis erzeugt wird. Innerhalb dieses Zwischenergebnisses
wird dann die zweite Bedingung angewendet und so das Ergebnis weiter
verkleinert. Statt dessen werden aber nacheinander die Datensätze
bearbeitet und alle Bedingungen pro Datensatz angewandt um direkt zu
entscheiden, ob sie in die Ergebnismenge kommen oder nicht. Das spart
Arbeitsspeicher und bedeutet, dass es egal ist, in welcher Reihenfolge
die Bedingungen in der Abfrage stehen. Ich gehe davon aus, dass der
Optimizer "einfache" Bedingungen wie Integer-Vergleiche vorzieht (sofern
möglich) und schwierige Bedingungen wie ein LIKE '%..%' eher hinten
anstellt um *pro Datensatz* möglichst schnell zu der Entscheidung
Ja/Nein zu kommen.

Diese Freiheit umzusortieren bedeutet aber auch, dass du dem Optimizer
dein Wissen um die Wertverteilung nicht mitteilen kannst, solange du
keinen Index auf die Spalte legst. Der Optimizer ist nur in der Lage zu
entscheiden wie schwer ein einzelner Vergleich ist, nicht wie gut er das
Ergebnis filtert.

Die Frage, die sich mir gerade stellt: *Hast* du aktuell ein Problem,
das du, wie du es beschrieben hast, lösen möchtest? Oder glaubst du nur,
dass da irgendwann unter irgendwelchen vagen Umständen ein Problem
entstehen könnte und begibst dich auf das dünne Eis der "Premature
optimization"?

> Eine weitere Frage hätte ich noch zur Optimierung: Wenn ich ein Statement
> ohne Limit ausführe, um die Anzahl der Suchergebnisse zu ermitteln, und
> danach noch einmal die selbe Abfrage mit Limit mache (um in Webseiten durch
> die Ergenbnisse zu blättern), wie kann ich es dann erreichen, dass MySQL das
> Ergebnis zwischenspeichert und nicht die ganze Abfrage noch einmal von vorne
> abarbeitet? (Damit pro Seitenaufruf nur ein Datenbankaufruf statt zwei
> notwendig sind.)

Du suchst SELECT SQL_CALC_FOUND_ROWS und anschließend SELECT FOUND_ROWS().

Grüße
Kai

--
This signature is left as an exercise for the reader.

Re: Logische Verknüpfungen in SQL-Statements

am 08.01.2007 22:21:19 von Werner Bauer

Axel Schwenke schrieb:
> "Christian Ratsch" wrote:
>>wie kann ich es dann erreichen, dass MySQL das
>> Ergebnis zwischenspeichert und nicht die ganze Abfrage noch einmal von=
vorne
>> abarbeitet?
>=20
> Du sparst die Query ohne Limit und verwendest SQL_CALC_FOUND_ROWS:

wir die Query nicht sowieso zwischengespeichert im Querycache? In meinen =

Apps jedenfalls bringt SQL_CALC_FOUND_ROWS in _solchen_ Fällen gar nix.=
=20
Nur dann, wenn ich nur die Anzahl brauche ...

W

Re: Logische Verknüpfungen in SQL-Statements

am 08.01.2007 23:06:03 von Kai Ruhnau

werner bauer wrote:
> Axel Schwenke schrieb:
>> "Christian Ratsch" wrote:
>>> wie kann ich es dann erreichen, dass MySQL das
>>> Ergebnis zwischenspeichert und nicht die ganze Abfrage noch einmal
>>> von vorne
>>> abarbeitet?
>>
>> Du sparst die Query ohne Limit und verwendest SQL_CALC_FOUND_ROWS:
>
> wir die Query nicht sowieso zwischengespeichert im Querycache?

Im Query cache wird ein Hash der Query und deren Ergebnis abgespeichert.
Wenn du die gleiche Abfrage einmal mit und einmal ohne LIMIT machst,
dann sind das für den Query cache zwei verschiedene Abfragen. Es ist
aber durchaus so, dass andere Caches die Daten zwischenspeichern (und
sei es der Plattencache vom OS)

> In meinen
> Apps jedenfalls bringt SQL_CALC_FOUND_ROWS in _solchen_ Fällen gar nix.
> Nur dann, wenn ich nur die Anzahl brauche ...

Wenn ich den OP richtig verstanden habe, möchte er doch genau das.

Ein

SELECT ... LIMIT n,m

und ein

SELECT COUNT(*)

nacheinander. Das erste für die aktuelle Seite beim "blättern", das
Zweite für die Anzahl der Seiten. Genau für diesen Fall wurde die
Kombination von

SELECT SQL_CALC_FOUND_ROWS ... LIMIT n,m

und anschließendem

SELECT FOUND_ROWS()

eingeführt. Die zweite Abfrage arbeitet nur mit Ergebnissen, die die
erste Abfrage bereits quasi nebenbei gesammelt hat.

Oder verstehe ich deinen Einwand falsch?

Grüße
Kai

--
This signature is left as an exercise for the reader.

Re: Logische Verknüpfungen in SQL-Statements

am 09.01.2007 15:46:09 von Werner Bauer

Kai Ruhnau schrieb:
> Im Query cache wird ein Hash der Query und deren Ergebnis abgespeichert=
.
> Wenn du die gleiche Abfrage einmal mit und einmal ohne LIMIT machst,=20
> dann sind das für den Query cache zwei verschiedene Abfragen. Es ist =

> aber durchaus so, dass andere Caches die Daten zwischenspeichern (und=20
> sei es der Plattencache vom OS)
> ...

> Oder verstehe ich deinen Einwand falsch?


Nein, Kai, du verstehts das Ganze besser wie ich ;-)

Werner

Re: Logische Verknüpfungen in SQL-Statements

am 09.01.2007 21:40:52 von Christian Ratsch

Kai Ruhnau schrieb:
> Da auf keinem der Felder ein Index liegt, *sind* alle Bedingungen gleich
> schwer in folgender Hinsicht: Um die Zeilen herauszufiltern auf die alle
> Bedingungen zutreffen, müssen sämtliche Zeilen geladen werden und in
> sämtlichen Zeilen die Bedingungen überprüft werden. Das Produkt aus
> Zeilen und komplexität der Bedingungen ändert sich nicht.
>
> Ich denke, so wie du es schreibst, gehst du davon aus, dass zunächst
> alle Zeilen geladen werden, dann eine erste Bedingung überprüft wird und
> ein Zwischenergebnis erzeugt wird.

Nein, ich habe mir das schon so vorgestellt, wie Du es beschrieben hast.
War einfach davon ausgegangen, dass ich durch die Reihenfolge im
Statement die Überprüfung pro Datensatz schon möglichst früh abbrechen
kann, wenn eine einfache Bedingung nicht erfüllt ist.

> Die Frage, die sich mir gerade stellt: *Hast* du aktuell ein Problem,
> das du, wie du es beschrieben hast, lösen möchtest? Oder glaubst du nur,
> dass da irgendwann unter irgendwelchen vagen Umständen ein Problem
> entstehen könnte und begibst dich auf das dünne Eis der "Premature
> optimization"?

Ich befürchte, dass sich das Problem bei steigenden Zugriffszahlen
stellt. Aktuell habe ich es noch nicht. Jedoch will ich, bevor ich z.B.
irgendwann auf schnellere/teurere Hardware umsteigen muss, den Code
soweit wie möglich optimieren (wovon ich jedoch nicht viel Ahnung habe...).
Wo finde ich im Web gute Tutorials, die sich speziell mit (möglichst
sinnvollen) Indizes beschäftigen? Kannst Du da vielleicht eins besonders
empfehlen?

>> Eine weitere Frage hätte ich noch zur Optimierung: Wenn ich ein
>> Statement ohne Limit ausführe, um die Anzahl der Suchergebnisse zu
>> ermitteln, und danach noch einmal die selbe Abfrage mit Limit mache
>> (um in Webseiten durch die Ergenbnisse zu blättern), wie kann ich es
>> dann erreichen, dass MySQL das Ergebnis zwischenspeichert und nicht
>> die ganze Abfrage noch einmal von vorne abarbeitet? (Damit pro
>> Seitenaufruf nur ein Datenbankaufruf statt zwei notwendig sind.)
>
> Du suchst SELECT SQL_CALC_FOUND_ROWS und anschließend SELECT FOUND_ROWS().

Danke an dieser Stelle auch stellvertretend an alle anderen, die den
Hinweis hiearuf gaben!

Gruß,
Christian

Re: Logische Verknüpfungen in SQL-Statements

am 10.01.2007 01:26:34 von Kai Ruhnau

Christian Ratsch wrote:
> Kai Ruhnau schrieb:
[Beschleunigung der Bedingungsabarbeitung]
>> Die Frage, die sich mir gerade stellt: *Hast* du aktuell ein Problem,
>> das du, wie du es beschrieben hast, lösen möchtest? Oder glaubst du
>> nur, dass da irgendwann unter irgendwelchen vagen Umständen ein
>> Problem entstehen könnte und begibst dich auf das dünne Eis der
>> "Premature optimization"?
>
> Ich befürchte, dass sich das Problem bei steigenden Zugriffszahlen
> stellt. Aktuell habe ich es noch nicht. Jedoch will ich, bevor ich z.B.
> irgendwann auf schnellere/teurere Hardware umsteigen muss, den Code
> soweit wie möglich optimieren (wovon ich jedoch nicht viel Ahnung habe...).
> Wo finde ich im Web gute Tutorials, die sich speziell mit (möglichst
> sinnvollen) Indizes beschäftigen? Kannst Du da vielleicht eins besonders
> empfehlen?

Ich fürchte, das Indizieren einer Datenbank ist eine Wissenschaft für
sich, bei der man mit viel Erfahrung (manche nennen es auch "glückliches
Händchen") eine ganze Menge erreichen kann.

Mein Vorgehen an der Stelle ist so:
- Da ich mit InnoDB arbeite, sind alle Fremdschlüsselfelder ohnehin mit
einem Index belegt, ebenso wie der Primary Key.
- Einige Constraints lassen sich in Form eines Unique-Index modelieren,
das mache ich auch direkt.
- Bei einigen häufig besuchten Übersichtsseiten schaue ich mir von vorne
herein an, welche Felder abgefragt werden (das fällt schon in den
Bereich der Erfahrung)
- Ansonsten erstelle ich Indizes nur dann, wenn ich weiß, dass ich sie
brauche.

Gerade der letzte Punkt läuft bei mir mit einer Entwicklungsdatenbank,
die möglichst nah an die Datenmenge und -verteilung des Produktivsystems
herankommt (Kopie), um schon früh entsprechende Engpässe zu bemerken.
Dann zu entscheiden, welcher Index mit welchen Feldern in welcher
Reihenfolge, ist nur nach sehr genauem Studium der Ausgabe von "EXPLAIN"
und des Handbuchs (mehr oder weniger das gesamte Kapitel 7
http://dev.mysql.com/doc/refman/5.0/en/optimization.html) viel
Ausprobieren und dabei einer Menge Erfahrung möglich. Pauschale Tipps
gibt's da nicht wirklich. Auf der anderen Seite bin ich auch immer
wieder überrascht, wie viel ein Index dann doch bringt. (Vom
Serverkiller zur Millisekundenangelegenheit, zuletzt von 20 Sekunden auf
0.1 Sekunden - ein einziger kombinierter Index, von dem verschiedene
Präfixe benutzt wurden)

Das schöne aber ist, dass man (üblicherweise) einen Index dann
nachrüsten kann, wenn man ihn braucht. Will sagen: Sorge dafür, dass
deine Anwendung bzw. MySQL erkennt, wenn Abfragen zu lange dauern (slow
query log bzw. Zeitmessungen in der Anwendung) und kümmere dich dann
drum, wenn dir deine Kontrollstufen mitteilen, dass es sein muss.

Ach ja: Manchmal muss man ein DBMS auch davon überzeugen, dass man Recht
hat ;-)
http://bugs.mysql.com/bug.php?id=25407

Grüße
Kai


--
This signature is left as an exercise for the reader.