Abfrage über sehr sehr große tabelle

hallo,

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?

viele grüße,
July

Moin, July,

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.

Gruß Ralf

Hallo Ralf,

danke für Deine Antwort. Wie kann ich herausfinden, ob es ein Äquivalent zu „Explain“ gibt? Das kennt es scheinbar nicht (Microsoft SQL Server).

Grüße,
July

Hallo,

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]

Hallo Ulrich,

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).

Hallo,

wichtig ist auch, dass die Stastistiken der Tabellen aktuell sind, damit der SQL Server den richtigen Plan wählt.

Ggf. muss man regelmäßig die Statistiken aktualisieren.

Gruß

Holygrail

Hi!

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.

Grüße,
Tomh