Als PDF Downloaden!

Werbung
Tipps & Tricks: April 2014
Bereich:
SQL, PL/SQL
Erstellung:
04/2014 HA
Versionsinfo:
12.1
Letzte Überarbeitung:
04/2014 HA
Zeilenbegrenzung in 12c - Pagination leicht gemacht
Wer je Daten für eine Web-Applikation bereitstellen musste, kennt das Problem der Pagination. In der Regel holt
das Frontend ja nur die Daten, die auf eine Seite passen, und erst wenn mehr angefordert werden, werden auch
mehr geholt. Das stellt den Programmierer vor die Schwierigkeit, die Daten entprechend "mundgerecht" zu
liefern. Entscheidend dabei ist in jedem Fall eine absolut eindeutige Sortier-Reihenfolge.
Ein klassischer von Tom Kyte u. a. hier beschriebener Ansatz über ROWNUM sieht dann so aus:
select *
from ( select /*+ FIRST_ROWS(n) */
a.*, ROWNUM rnum
from ( your_query_goes_here,
with order by ) a
where ROWNUM <=
:MAX_ROW_TO_FETCH )
where rnum >= :MIN_ROW_TO_FETCH;
Anmerkung: Für die folgenden Beispiele wurde eine Tabelle OBJECT_TAB als Kopie von ALL_OBJECTS erstellt.
Angewendet auf diese Tabelle sähe ein Select, der die Zeilen 11 bis 20 holt, z. B. so aus:
SELECT object_id, object_name
FROM (SELECT a.*, ROWNUM rnum
FROM ( SELECT *
FROM object_tab
ORDER BY object_id) a
WHERE ROWNUM <= 20)
WHERE rnum >= 11;
Der Ausführungsplan zeigt, dass der Optimizer hier mit Stopkeys arbeitet:
Execution Plan
---------------------------------------------------------0
SELECT STATEMENT Optimizer Mode=ALL_ROWS (Cost=1872 Card=20 Bytes=1 K)
1 0
VIEW (Cost=1872 Card=20 Bytes=1 K)
2 1
COUNT STOPKEY
3 2
VIEW (Cost=1872 Card=65 K Bytes=4 M)
4 3
SORT ORDER BY STOPKEY (Cost=1872 Card=65 K Bytes=6 M)
5 4
TABLE ACCESS FULL OBJECT_TAB (Cost=290 Card=65 K Bytes=6 M)
Muniqsoft GmbH
Schulungszentrum, Grünwalder Weg 13a, 82008 Unterhaching, Tel. 089 / 679090-40
IT-Consulting & Support, Witneystraße 1, 82008 Unterhaching, Tel. 089 / 6228 6789-0
Seite 1 von 4
Anmerkung: Um Zeilenumbrüche in der Darstellung zu verhindern, wurden überflüssige Leerzeichen und
Schema-Angaben aus dem Ausführungsplan entfernt.
Im PL/SQL-Umfeld würde eine entsprechende Prozedur - stark vereinfacht - z. B. so aussehen:
CREATE PROCEDURE test_1 (p_from
IN
NUMBER,
p_until
IN
NUMBER,
p_result
OUT SYS_REFCURSOR)
AS
BEGIN
OPEN p_result FOR
SELECT object_id, object_name
FROM (SELECT a.*, ROWNUM rnum
FROM ( SELECT object_id, object_name
FROM object_tab
ORDER BY object_id) a
WHERE ROWNUM <= p_until)
WHERE rnum >= p_from;
END test_1;
/
Da man jedoch gerade bei Suchmasken in der Regel mit dynamischen SQL arbeiten muss, ist das wohl etwas
näher dran:
CREATE PROCEDURE test_2 (p_from
IN
NUMBER,
p_until
IN
NUMBER,
p_result
OUT SYS_REFCURSOR)
AS
v_sql VARCHAR2 (4000 CHAR);
BEGIN
v_sql := 'SELECT object_id, object_name
FROM (SELECT a.*, ROWNUM rnum
FROM ( SELECT object_id, object_name
FROM object_tab
-- WHERE .....
ORDER BY object_id) a
WHERE ROWNUM <= :1)
WHERE rnum >= :2';
OPEN p_result FOR v_sql USING p_until, p_from;
END test_2;
/
Das funktioniert zwar, ist aber nicht direkt intuitiv.
Mit Version 12c hat nun Oracle eine neue Klausel zur Begrenzung der Zeilen eingeführt, die die Syntax in
solchen Fällen deutlich vereinfacht.
Angegeben werden können dabei:
OFFSET: Ein Startpunkt, ab wo geliefert werden soll;
Muniqsoft GmbH
Schulungszentrum, Grünwalder Weg 13a, 82008 Unterhaching, Tel. 089 / 679090-40
IT-Consulting & Support, Witneystraße 1, 82008 Unterhaching, Tel. 089 / 6228 6789-0
Seite 2 von 4
wird diese Angabe weggelassen, gilt OFFSET = 0, also Beginn beim ersten Datensatz der
Ergebnismenge
FETCH: Anzahl oder Prozentsatz an Zeilen, die geholt werden sollen;
wird diese Angabe weggelassen, so werden alle Zeilen ab <OFFEST + 1> geholt
Das obige Beispiel würde in 12c so aussehen:
SELECT object_id, object_name
FROM object_tab
ORDER BY object_id
OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY;
Glaubt man dem Ausführungsplan, so ist diese Abfrage nicht nur wesentlich lesbarer, sondern auch noch
performanter:
Execution Plan
---------------------------------------------------------0
SELECT STATEMENT Optimizer Mode=ALL_ROWS (Cost=860 Card=65 K Bytes=6 M)
1 0
VIEW (Cost=860 Card=65 K Bytes=6 M)
2 1
WINDOW SORT PUSHED RANK (Cost=860 Card=65 K Bytes=1 M)
3 2
TABLE ACCESS FULL OBJECT_TAB (Cost=289 Card=65 K Bytes=1 M)
Anmerkung: Auch hier wurden überflüssige Leerzeichen und Schema-Angaben aus dem Ausführungsplan
entfernt.
Eine Prozedur analog zu oben würde dann so aussehen:
CREATE OR REPLACE PROCEDURE test (p_offset IN
NUMBER,
p_lines
IN
NUMBER,
p_result
OUT SYS_REFCURSOR)
AS
v_sql VARCHAR2 (4000 CHAR);
BEGIN
v_sql := ' SELECT object_id,object_name
FROM object_tab
-- WHERE .....
ORDER BY object_id
OFFSET :1 ROWS FETCH NEXT :2 ROWS ONLY';
OPEN p_result FOR v_sql USING p_offset, p_lines;
END test;
/
Wesentlich lesbarer, oder?
Welche Möglichkeiten bietet die neue Klausel noch? Neben dem oben angegebenen <n> ROWS kann auch ein
Prozentsatz mitgegeben werden mit <n> PERCENT ROWS. Das würde dann so aussehen:
SELECT object_id, object_name
Muniqsoft GmbH
Schulungszentrum, Grünwalder Weg 13a, 82008 Unterhaching, Tel. 089 / 679090-40
IT-Consulting & Support, Witneystraße 1, 82008 Unterhaching, Tel. 089 / 6228 6789-0
Seite 3 von 4
FROM object_tab
ORDER BY object_id
OFFSET 10 ROWS FETCH NEXT 10 PERCENT ROWS ONLY;
Sollte die Sortierung nicht eindeutig sein (und auch nicht sein müssen), so kann man angeben, dass alle
Datenätze mit ausgegeben werden sollen, die den gleichen Wert haben wie der zuletzt geholte. Dazu gibt man
statt ONLY an WITH TIES. Der Effekt sei hier gezeigt an der allseits bekannten Tabelle SCOTT.EMP:
SELECT ename, sal
FROM scott.emp
ORDER BY sal DESC
FETCH NEXT 2 ROWS ONLY;
ENAME
SAL
---------- ---------KING
5000
SCOTT
3000
SELECT ename, sal
FROM scott.emp
ORDER BY sal DESC
FETCH NEXT 2 ROWS WITH TIES;
ENAME
SAL
---------- ---------KING
5000
SCOTT
3000
FORD
3000
Diese neue Klausel ist prinzipell nicht abhängig von der ORDER BY-Klausel. Ihre vollen Möglichkeiten entfaltet
sie aber nur hier.
Mehr zu diesem Thema erfahren Sie in unserer Schulung Oracle Neuerungen 12c, schauen Sie doch einfach
vorbei :-)
Muniqsoft GmbH
Schulungszentrum, Grünwalder Weg 13a, 82008 Unterhaching, Tel. 089 / 679090-40
IT-Consulting & Support, Witneystraße 1, 82008 Unterhaching, Tel. 089 / 6228 6789-0
Seite 4 von 4
Herunterladen