Hallo Theo!
Kurioser Weise - ich versuchs mal im Konjunktiv - glaube ich
dies
genauso verstanden zu haben (wie gesagt ich kann mich irren.)
Im Rahmen einer LehrVeranstaltung über GIS wurde dies so
dargestellt.
Ich hoffe du irrst dich.
Nicht bei 2 Tabellen es waren schon ein paar mehr.
Vorweg: Die Terminologie ist bei mir schwer Oracle-lastig. Einige punkte heissen bei anderen RDBMSs sicher anders, was sie tun ist aber eigentlich immer das Gleiche.
Das Prinzip bleibt aber immer das gleiche, auch wenn der Optimizer bei mehr Tabellen auch mehr mögliche Execution Paths (vielleicht sollte ich gleich auf Englisch antworten?) berücksichtigen muss. Das Problem dabei ist: Die Datenbank weiss potentiell wesentlich mehr über Tabelln, Indices etc. als du. Wenn also die Datenbank einen Zugriffsplan erstellt, dann ist der schon aus diesem Grund potentiell besser. Zumindest bei neueren Versionen von Oracle (ab ~9iR2) liegt der Optimizer schon fast immer richtig. Ausnahme: Er weiss bestimmte Dinge nicht, die ich aber weiss/mein Schemadesign ist suboptimal und vereinzelte Irrtümer (schlisslich ist auch bei Oracle nicht alles perfekt
.
Doch der Grundton war genauso. Schneide im ersten Schritt ab,
was deine Ergebnismenge voraussichtlich am Kleinsten werden
lässt.
Schon, aber wie weiter? Die Ergebnismenge dann auf den Client holen? Dort selber weiterwerken? Das KANN nicht schneller sein als nur die Daten vom Server zu holen, die man braucht.
Vielleicht ist das mit 50% etwas weniger sinnvoll.
Gebe ich ja zu. Aber das Prinzip bleibt das gleiche, egal ob das jetzt 50 oder 99,5 % sind.
-aber
gerade bei den Gis hast Du reichliche Datenmengen, die auch
bei uns auch über Oracle laufen. Wenn ich also schon im ersten
Schritt 99,5% ausschliessen kann, dann scheint mir das nicht
zwangsläufig abwegig.
Schon, aber wie schon gesagt, wie weiter? Mir fällt auf die schnelle keine Möglichkeit ein das Ergebnis eines SELECTs weiter zu bearbeiten, ohne es auf den Client zu holen. Vielleicht habe ich da jetzt ja nur ein Brett vor dem Kopf.
Andererseits: Der Server hat folgende Möglichkeiten, ein Ergebnis zu ermitteln:
a) Er liest die gesamte Tabelle und vergleicht bei jeder Row für jedes Kriterium. Welches der Kriterien er zuerst prüft weiss meine Applikation zwar nicht, aber es kann ihr auch völlig egal sein, der Aufwand liegt hier ohnehin im Lesen der Daten, weniger im Vergleich.
b) Er hat für ein oder mehrere Kriterien einen Index. Dann liest er (selten/manchmal/oft/immer) zuerst natürlich den Index und scheidet so schon mal alle Rows aus, die nicht diesem Kriterium entsprechen. Mit zusammengesetzten Indices kann ich so auch schon mal mehrere Attribute verknüpfen. Was dann noch übrigbleibt geht er wie in a) durch. Wenn der Server vernünftige Statistiken hat, dann weiss er auch, welche Kriterien am selektivsten sind, also wird er (wahrscheinlich) auch diese zuerst auswerten, während deine Applikation da zwar oft eine Ahnung hat, aber nix definitives nicht weiss…
…aber das geht hier eigentlich zu weit.
Ich habe lediglich geschrieben, da ich vor einiger Zeit ein
Problem durch Nacheinanderlegung deutlich besser durchführen
konnte. In dieser Sache bot sich das als Antwort an.
Das Problem (bzw. die Lösung) würde mich wirklich interessieren. War das etwa so wie oben beschrieben - oder eher sowas hier: „SELECT a.* FROM (SELECT * FROM my_table a WHERE bedingung1) WHERE bedingung2“? Letzteres führt übrigens bei mir immer zum gleichen Execution Path, der Optimizer lässt sich hier also nicht austricksen 
Welche kartesische Ergebnismenge? Wenn ich schreibe „SELECT
a.*, b.* FROM a, b WHERE a.primary_key=b.foreign_key AND
a.primary_key=4711“ dann bildet die DB mit hoher
Wahrscheinlichkeit keine kartesische Ergebnismenge um
Richtig. Nimm aber mal Abfragen die sich auf einige Tabellen
mehr beziehen. Wie schliesst Du aus, dass nicht jedesmal
alles, kombiniert mit jedem, auf ein Attribut durchsucht wird.
Prinzipiell hat die DB zwei Möglichkeiten einen Join durchzuführen: HASH JOINs (die Rows aus den verschiedenen Tabellen gelesen, nach dem Vergleichskriterium sortiert und dann gejoint) und NESTED LOOPs (Für jede Row aus Tabelle A wird ein Teil/alles von Tabelle B gelesen und auf das Vergleichskriterium geprüft). Wenn du mit dem kartesischen Produkt die Nested Loops meinst, dann liegst du ja im Prinzip richtig, allerdings können auch die ihren Vorteil haben.
Ein Beispiel (das ich von Herrn Thomas Kyte, „Effective Oracle by Design“ gestohlen habe):
Man nehme eine Tanzschule mit je 1000 Männlein und Weiblein. Diese sollen der Grösse nach zu Paaren zusammengestellt werden. Erster Ansatz: Ich suche mir mal den grössten Mann und danach die grösste Frau. Das geht relativ schnell und ich habe recht flott mein erstes Paar (meine erste Row). Brauche ich nur 5 Paare, dann wird das wohl der Weg sein, den ich wählen werde. Brauche ich aber alle 1000 Paare, dann scheint eine andere Vorgehensweise effizienter: Ich sortiere alle Männer der Grösse nach, danch (oder davor) die Frauenund stelle sie in einer Reihe auf. Diese Sortierung wird relativ lange dauern (im Vergleich zum finden des jeweils grössten), aber wenn ich das mal habe, dann habe ich fast sofort auch alle Paare gefunden. Ersteres entspricht in etwa den NESTED LOOPs, letzteres dem HASH JOIN.
Daraus ergibt sich: Auch das kartesische Produkt (auch wenn es nicht wirklich eines ist, weil ja das erste Paar beim zweiten Durchgang nicht mehr berücksichtigt wird) kann so seine Vorteile haben, je nachdem, was ich von meiner DB will. Wenn ich jetzt noch einen Weg finde, das meiner DB mitzuteilen, dann habe ich auch schon gewonnen. Und Wunder: Zumindest unter Oracle gibt es dafür sogar (mindestens) zwei Möglichkeiten: Query hints und OPTIMIZER_GOAL…
Ein SELECT von einer Row ist potentiell beinahe
gleich schnell, egal ob die Tabelle eine oder eine Million
Einträge hat.
ich habe da leise Zweifel, vor allem wenn zwei Server
angesprochen werden.
Unter Oracle hat ein B*Tree-Index in der Regel 2-3 Ebenen, und zwar auch noch bei 1 Mio Datensätzen. Es müssen also bei einem Index-Read idR 3-4 Blocks gelesen werden - (fast) unabhängig von der Anzahl der Rows in der Tabelle.
Wo ich dir natürlich recht geben muss: Wenn der Zugriff über einen DB-Link erfolgt, dann kann auf der Remote-DB in vielen Fällen nur ein Full-Table-Scan (FTS) durchgeführt werden. Auskunft darüber gibt mir übrigens wieder mein herzallerliebster Execution Plan. Wenn diese FTS auf wirklich grosse tabellen zugreifen, dann sollte ich mir aber ohnehin Gedanken über Replikation machen, damit lässt sich auch dieses Porblem beheben…
ich habe das Gefühl, dass ich gerade
wieder was dazulerne …
Ich lass mich gern aufklären.
Ich hoffe mich einigermassen verständlich ausgedrückt zu haben…
Gruß
Martin