vielleicht kann mir hier jemand weiterhelfen. ich bin nicht sehr geübt im umgang mit datenbankabfragen und scheitere momentan an einer m.E. nach kleinen aufgabe.
um es zu abstrahieren, folgender sachverhalt.
ich habe eine tabelle hersteller (alle mit entsprechender ID und fremdschlüssel), eine tabelle produkte (ein produkt kann immer einem hersteller zugeordnet werden), eine tabelle lieferung (eine lieferung wird immer einem produkt zugeordnet, diese tabelle kann sehr sehr groß werden - mehrere millionen einträge, selbst wenn man die einträge auf einen einzelnen hersteller beschränkt) und eine tabelle lieferdienst (jede lieferung wird von einem lieferdienst erledigt).
nun möchte ich für einen ausgewählten hersteller abfragen, welche lieferdienste er in anspruch genommen hat. ich komme also um die riesige tabelle der lieferung nicht drumrum. gibt es trotzdem einen weg eine schnelle abfrage zu generieren?
mein bisheriger ansatz sah in etwa so aus:
select lieferdienst.name from lieferdienst, lieferung, produkt, hersteller
where hersteller.name = „hersteller_1“ and
hersteller.id = produkt.hersteller_id and
produkt.id = lieferung.produkt_id and
lieferung.lieferdienst_id = lieferdienst.id
group by lieferdienst.name
irgendwelche verbesserungsvorschläge? oder anregungen?
die Geschwindigkeit hängt davon ab, ob die Tabellen indiziert sind. Schlüssel sind es von selbst, die Indizes auf Fremdschlüssel musst Du anlegen.
Die Query passt schon. Optimieren lässt sich da nichts, wenn überhaupt, dann macht das der Optimizer des DBMS. Wie die Query aufgelöst wird, zeigt Dir der Befehl EXPLAIN - so heißt er bei DB2, ähnliche Funktionen haben alle großen DBMS.
ein kurzes Googeln nach „Explain mssql“ bringt folgendes :
Query Analyzer will show you the execution plan for SQL statements (choose
Query / Display Estimated Execution Plan) or you can use the SET
SHOWPLAN_TEXT ON statement to return the text of the plan when you execute a
query.
The actual cached plans aren’t exposed to be queried directly but you can
see what objects have been cached in the master…syscacheobjects system
table.
Gruss
[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]
vielen Dank für den Hinweis; ich werd es mir gleich genauer anschauen. In der Zwischenzeit bin ich über folgende Lösung gestolpert:
SELECT lieferdienst.name FROM lieferdienst
WHERE EXISTS (SELECT * FROM lieferung, produkt, hersteller
WHERE hersteller.name = „hersteller_1“ AND
hersteller.id = produkt.hersteller_id AND
produkt.id = lieferung.produkt_id AND
lieferung.lieferdienst_id = lieferdienst.id)
(Ich hoffe ich hab keinen Fehler gemacht beim umtippen).
SELECT lieferdienst.name FROM lieferdienst
WHERE EXISTS (SELECT * FROM lieferung, produkt, hersteller
WHERE hersteller.name = „hersteller_1“ AND
hersteller.id = produkt.hersteller_id AND
produkt.id = lieferung.produkt_id AND
lieferung.lieferdienst_id = lieferdienst.id)
Mein persönliche Erfahrung ist, das einzelne Sub-selects wesentlich performanter als ein Über-Alles-Join ist, in Deinen Fall könntest mal das ausprobieren (falls dies unter MS-SQL überhaupt funktioniert):
select ld.name
from lieferdienst ld,
(select lieferdienst\_id
from lieferung,
(select id
from produkt,
(select id
from hersteller
where name = "hersteller\_1") h
where h.id = hersteller\_id) p
where p.id = produkt\_id) l
where ld.id = l.lieferdienst.id
(Ich hab’s jetzt weder auf Syntax noch auf Semantik geprüft - sollte aber ungefähr so aussehen)
Noch schöner ist das Ganze, wenn anstatt „hersteller_1“ eine (Binde-)Variable genommen wird, den dann muß der Parser das Ganze lediglich einmal durchgehen, falls die Abfrage öfter läuft.
Die Indizes sollten hierfür jedenfalls trotzdem auch vorhanden sein.