2017-09-29 1 views
0

Ich verwende Oracle 11.2 und versuche, eine Auslagerungsabfrage auf einer Tabelle mit Millionen von Zeilen darin zu schreiben. Wenn ich andere Artikel lese, denke ich, dass ich den besten Ansatz gefunden habe, aber es verlangsamt sich, je höher die Seitenzahl ist.Oracle Paging auf große Tabelle mithilfe der Liste der Primärschlüssel

Das ist meine Lösung. Zuerst erhalte ich eine Liste von Primärschlüsselwerten (ID) für diese Datenseite. Ich bekomme dann alle anderen Tabellendaten, die diesen IDs entsprechen. Dies läuft jedoch immer noch langsam.

SELECT * 
FROM mytable 
WHERE ID IN (
    SELECT ID 
    FROM (
     SELECT ID, ROWNUM rnum 
     FROM (
      SELECT ID 
      FROM mytable 
      ORDER BY ID 
     ) results 
     WHERE ROWNUM <= 1000010 
    ) 
    WHERE rnum >= 1000001 
) 

Ausführungszeit: 30+ Sekunden.

Wenn ich die innere Abfrage separat tun und manuell die IDs der äußeren Abfrage übergeben, es ist viel schneller:

SELECT ID 
FROM (
    SELECT ID, ROWNUM rnum 
    FROM (
     SELECT ID 
     FROM mytable 
     ORDER BY ID 
    ) results 
    WHERE ROWNUM <= 1000010 
) 
WHERE rnum >= 1000001 

Execution Time: 0.2 seconds. 

Results: 
2134696, 
2134697, 
2134692, 
2134693, 
2134694, 
2134695, 
2134698, 
2134699, 
2134700, 
2134701 

SELECT * 
FROM mytable 
WHERE ID IN (
    2134696, 
    2134697, 
    2134692, 
    2134693, 
    2134694, 
    2134695, 
    2134698, 
    2134699, 
    2134700, 
    2134701 
) 

Execution Time: 0.03 seconds. 

Die erste Abfrage sollte so schnell wie die anderen 2 zusammen, aber es ist viel langsamer.

Kann jemand erklären, warum dies ist und eine bessere Lösung vorschlagen?

Antwort

2

Die erste Abfrage führt zwei Tabellen- (oder Index-) Scans (von Millionen von Zeilen) durch und fügt sie zusammen, um die Zeilen zu filtern.

Ihre zweite und dritte Abfrage führen jeweils einen einzelnen Tabellen- (oder Index-) Scan durch, aber sie verbinden sie nicht miteinander.

sollten Sie so etwas wie verwenden:

SELECT * 
FROM (
    SELECT r.*, ROWNUM rnum 
    FROM (
     SELECT * 
     FROM mytable 
     ORDER BY ID 
    ) r 
    WHERE ROWNUM <= 1000010 
) 
WHERE rnum >= 1000001 

die nur einen einzigen Table-Scan funktioniert.

In Oracle 12c können Sie:

SELECT * 
FROM  MYTABLE 
ORDER BY id 
OFFSET 1000000 ROWS FETCH NEXT 10 ROWS ONLY 
+0

Danke für die Antwort. Ich begann mit Ihrer Abfrage, aber es dauerte wiederum 30 Sekunden, um Ergebnisse zu liefern. Der schnellste Weg zur Zeit für meine Lösung ist, zuerst die Liste der IDs zu erhalten und dann eine separate Abfrage auszulösen, um die zugehörigen Daten zu erhalten. Es scheint mir verrückt, aber es funktioniert. Ich nehme an, dass Oracle 12 dies besser handhabt. – markvpc

+0

@markvpc Haben Sie einen Index für die Spalte 'ID'? – MT0

+0

Ja, es ist die Primärschlüsselspalte und ist sehr schnell zu holen. Das Problem tritt auf, wenn andere Daten in dieser Tabelle abgerufen werden. – markvpc

0

Der beste Weg für die Gesamt Datensätze erhalten zählen und Aufzeichnungen.

Änderung [YOURTABLENAME] Änderung 2 und 100 (2 "SEITENNR", 100 "perpage")

with 
XPARAMS as (select 2 "PAGENO", 100 "PERPAGE" from dual) 
,P2 as (select (XPARAMS.PAGENO-1)*XPARAMS.PERPAGE "STARTNO", XPARAMS.PAGENO*XPARAMS.PERPAGE "ENDNO" from XPARAMS) 
,D1 as (select * from [YOURTABLENAME] t order by ID) 
,DCOUNT as (select count(*) "TOTALCOUNT" from D1) 
,D2 as (select rownum "RN" , D1.* from D1) 
,D3 as (select D2.* from D2,P2 where D2.RN between P2.STARTNO and p2.ENDNO) 
select D3.RN, DCOUNT.TOTALCOUNT, XPARAMS.PAGENO, XPARAMS.PERPAGE, D3.* from D3,DCOUNT, XPARAMS 
Verwandte Themen