select a, b, c, d, … from tabelle
where a = (select min(a) from tabelle where a between [wert] and [wert])
dauert bei mehreren millionen eintraegen doch recht lange.
der datentyp von a ist number.
auf a liegt auch ein index.
gibt es vielleicht noch andere (und wenn ja welche) moeglichkeiten diese statement ein wenig zu beschleunigen??
mit rownum haben wir auch schon rumexperimentiert. leider habe ich die bedeutung dieses ein wenig falsch interpretiert. es funktioniert >> schneller.
wunderbar!!
zu bemerken ist bei diesem rownum leider ein kleiner nachteil:
man kann nur [Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]
Dumme Frage zum Tage, hat es einen bestimmten Grund warum du
statt:
SELECT a,b,c,d
FROM tabelle
WHERE
( a BETWEEN [wert] AND [wert] )
AND ( ROWNUM = 1 )
ORDER BY a ASC)
WHERE ROWNUM = 1
/
Die Variante über zwei SELECTs wählst?
Es gibt nur einen Grund - ich will das richtige Ergebnis.
Die Rownum wird direkt nach der FROM-Klausel vergeben. Wenn der kleinste Wert zufälliger Weise die kleinste Rownum hat, muss das aber nicht immer so sein. Mein Tipp - Testhalber mal den Index umgehen (… WHERE a+0 BETWEEN [wert] AND [wert] …) .
Anschließend den gesuchten Wert löschen und gleich wieder einfügen. Wenn du dein Statement jetzt noch einmal laufen läßt, könnte ein falsches Ergebnis rauskommen.
Gruß der Janus
PS: Abgesehen davon ist die Klammer nach der ORDER BY-Klausel und die zweite WHERE-Klausel falsch. Das Statement sollte so nicht laufen …
Oder doch nicht ganz, hab das jetzt interessehalber mal ausprobiert, hatte Datensätze 1 - 7, wollte zwischen 3 und 5. Erster Versuch mit und ohne Index brachte 3. Zweiter Versuch nach Löschen und Wiedereinfügen brachte 4.
Was ich jetzt nicht verstehe, vergibt er die ROWNUMs jetzt nur für Datensätze die in der Ergebnismenge (definiert durch die anderen Kriterien) drinnen sind oder für alle Datensätze die das FROM erzeugt (und war es damit Zufall, dass die ROWNUM 1 wieder in meinem Bereich lag und ich vier als Ergebnis bekommen habe)?
Warum ich da so nachbohre, ich hab diese ROWNUM erst einmal verwendet, das war ein DELETE in der Form:
LOOP
DELETE
FROM agg\_messages
WHERE msg\_parent IS NULL AND msg\_deleted = 1 AND ROWNUM
Das war gedacht um zu vermeiden, dass das Rollback-Segment überläuft (die hätte \> 1 Million Datensätze mit BLOB-Feldern löschen sollen).
D. h. da hätte mir es irgendwann passieren können, dass ich in einer Endlosschleife lande, weil die ersten Tausend Datensätze immer eigentlich gar nicht dem Selektionskriterium entsprechend, damit nichts gelöscht wird, als Abbruch der Schleife aber die Anzahl der Datensätze auf die das Kriterium insgesamt zutrifft genommen wird, also da schon noch welche da sein hätten können?
> PS: Abgesehen davon ist die Klammer nach der ORDER BY-Klausel
> und die zweite WHERE-Klausel falsch. Das Statement sollte so
> nicht laufen ...
Sorry, war Copy&:stuck\_out\_tongue\_winking\_eye:aste und ich hatte es dann nicht probiert. :smile:
Danke und Grüße, Robert
Das Problem bei WHERE rownum… und einer ORDER BY Klausel liegt darin, daß immer zuerst die WHERE Klausel angewandt wird, dann erst die ORDER BY.
Vielleicht wird es mit diesem Beispiel leichter zu verstehen:
"SELECT \* FROM my\_table;" liefert:
col\_1 col\_2
5 Zeile1
4 Zeile2
3 Zeile3
2 Zeile4
"SELECT \* FROM my\_table WHERE rownum
somit wird auch klar, daß Deine DELETE Anweisung (zumindest diesbezüglich) genau das macht, was Du Dir erwartest (also Blöcke von 1000 rows löschen).
Gruß,
Martin
P.S.: Ich habe im Beispiel vorausgesetzt, daß das Hinzufügen der WHERE Klausel das Ergebnis bezüglich der Reihenfolge der rows nicht verändert. In Wirklichkeit liefert ...where rownum
dauert bei mehreren millionen eintraegen doch recht lange.
das sollte es eigentlich nicht, wenn auf a ein Index liegt. Hast Du Dir mal den Execution Plan ausgeben lassen?
Versuche auch mal „…WHERE a >= [wert]“ statt mit BETWEEN, oder eine weitere Schachtelung („SELECT min(a) FROM (SELECT a … BETWEEN …)“). Beiden Varianten gebe ich allerdings nur eine geringe Chance; irgendwie glaube ich eher, dass der Index nicht verwendet wird.
Falls doch:
ALTER INDEX index_auf_a REBUILD ONLINE
das du das Exit mit dem Return umgehst finde ich extrem unsauber. Die If-Bedingung würde ich so schreiben:
IF SQL%NOTFOUND THEN …
Erfüllt den selben Zweck und ist sauberer. Eigentlich nur zwei Kleinigkeiten - im kommerziellen Umfeld kann es aber teuer werden. Weisst du sicherlich selber.
Gruß Janus
PS - Testfrage zum Thema Rownum (beziehen sich alle auf die EMP-Tabelle) :
Welche 3 Mitarbeiter verdienen am meisten ?
Welche 3 Mitarbeiter wurden als letztes eingestellt ?
Welche 3 Mitarbeiter kommen im Alphabet als erstens ?
Erfüllt den selben Zweck und ist sauberer. Eigentlich nur zwei
Kleinigkeiten
Danke, werde das nächste Mal dran denken. In diesem Fall hat es sich erledigt weil der Oracle-Admin der die DB betreut gemeint hat er hängt uns einfach ein entsprechend grosses Rollback-Segment ein und wir machen ein einfaches DELETE. :o)
PS - Testfrage zum Thema Rownum (beziehen sich alle auf die
EMP-Tabelle) :