zuviele Treffer in einer MYSQ Abfrage
Juergen
- datenbank
- mysql
Der erste Code wäre dieser:
SELECT id_lvl3
FROM
geodb_hierarchies a
WHERE
a.loc_id=72052
Da habe ich eine Treffer, was OK ist
und dann möchte ich aus eienr zweiten Tabelle noch einen Namen dazu suchen
SELECT
b.text_val
FROM
geodb_hierarchies a,
geodb_textdata b
WHERE
(id_lvl3 AND b.loc_id AND b.text_type=500100000)AND a.loc_id=72052
jetzt habe ich 20000 Treffer was eindeutig 19999 Treffer zuviele sibnd.
O Ne, oder! vor lauter Code habe ich ein AND mit einem = vertauscht.
SELECT
b.text_val
FROM
geodb_hierarchies a,
geodb_textdata b
WHERE
(id_lvl3 = b.loc_id AND b.text_type=500100000)AND a.loc_id=72052
Hi,
dein Problem hat sich ja gelöst, trotzdem würde ich dir empfehlen dir mal JOINs anzugucken.
Momentan ist es bei deinem Query so, dass alle Einträge miteinander unnötigerweise "kombiniert" werden. Bspw:
Tabelle A: id;name 1;hallo 2;du
Tabelle B: id;text 1;welt 2;bla
Durch dein JOIN (ich glaub das nannte man cross join?) würde das WHERE auf folgende Datensatzkombinationen geprüft werden: A.id;A.name;B.id;B.text 1;hallo;1;welt 1;hallo;2;bla 2;du;1;welt 2;du;2;welt
Bei mehr Datensätzen in den Tabellen würde das irgendwann zu einer riesigen Datensatzsammlung anhäufen.
Über andere JOINs kann sowas von Anfang an reduziert werden und den Datenbankaufruf beschleunigen.
MfG kackb00n
Nein, da verwechselst Du Theorie und Praxis. Jürgens Query ist semantisch ein JOIN.
Natürlich ist es in der Coddschen Theorie so, dass eine Query mit zwei Tabellen im FROM zunächst mal zum kartesischen Produkt aufgespannt wird, an Hand der WHERE Angaben selektiert und schließlich basierend auf der SELECT-Liste projiziert wird.
Der DB Server weiß aber genauso gut wie wir, dass dieses Vorgehen im Allgemeinen blödsinnig ist. Queries laufen durch einen Optimizer, der basierend auf Statistiken und Schmierfett (=Indexe) einen hoffentlich optimalen Zugriffspfad findet (den man sich per EXPLAIN-Befehl auf mehr oder weniger verständliche Art darstellen lassen kann). Wie man einen solchen Optimizer baut, ist teils durch die Relationale Algebra vorgegeben, teils aber auch Geschäftsgeheimnis der jeweiligen Anbieter von DB-Servern.
Ob ich nun
SELECT a.dings, b.bums FROM tab1 a, tab2 b WHERE a.id = b.ref_id
schreibe oder
SELECT a.dings, b.bums FROM tab1 a JOIN tab2 b ON a.id = b.ref_id
das ist dem Optimizier komplett egal, es ist semantisch beide Male ein INNER JOIN und wird normalerweise in eine "nested loop" übersetzt. Wer in dieser Schleife innen und wer außen ist, entscheidet sich an Hand von Table-Größen und Vorhandensein von Indexen zur Laufzeit.
Nested Loop heißt, als Pseudocode:
foreach (satz in tab1) {
foreach (satz in tab2 wo b.ref_id = a.id)
(a.dings, b.bums) in Ausgaberelation schreiben
}
Ob "satz in tab1" per einfachem Table-Scan, per Index-sortiertem Table-Scan, oder per Index-Scan ermittelt wird, ist mal wieder eine Optimizer entscheidung.
Ob "satz in tab2 wo b.ref_id = a.id" ein Table-Scan, ein Direktzugriff per Index oder ein reiner Index-Zugriff ist, ebenfalls.
Und selbst wenn der Optimizer sich für einen Table-Scan entscheidet, kann das immer noch die fixeste Lösung sein, wenn die Tables so klein sind, dass der Server sie im RAM halten kann. Von Besonderheiten wie spaltenorientierter Speicherung mal ganz abgesehen...
Reine Index-Zugriffe finden dann statt, wenn die Datenfelder, die in die Ausgaberelation gehören, Teil des Index sind, über den gelesen wird. Dann greift er auf die eigentliche Table gar nicht mehr zu.
Rolf
Moin Juergen,
WHERE (id_lvl3 AND b.loc_id AND b.text_type=500100000)AND a.loc_id=72052
Bildest du hier nicht eine Vereinigungsmenge über verschiedene und vor allem voneinander unabhängige Einträge?
Viele Grüße
Robert
Ja, beim genaueren Hinsehen, ist nichts richtiges herausgekommen ;-)