Frage

Ich habe eine SQL-Abfrage, die etwa wie folgt aussieht:

SELECT * FROM(
    SELECT
        ...,
        row_number() OVER(ORDER BY ID) rn
    FROM
        ...
) WHERE rn between :start and :end

Im Wesentlichen ist es die ORDER BY-Teil, die Dinge zu verlangsamen wird. Wenn ich es entfernen waren, geht die EXPLAIN Kosten nach unten durch eine Größenordnung (über 1000x). Ich habe dies versucht:

SELECT 
    ...
FROM
    ...
WHERE
    rownum between :start and :end

Aber das gibt nicht korrekte Ergebnisse. Gibt es eine einfache Möglichkeit, dies zu beschleunigen? Oder werde ich etwas mehr Zeit mit dem EXPLAIN-Tool verbringen?

War es hilfreich?

Lösung

ROW_NUMBER ist ziemlich ineffizient in Oracle.

Siehe den Artikel in meinem Blog für Leistungsdetails:

Für Ihre spezifische Anfrage, würde ich Ihnen empfehlen, es zu ersetzen mit ROWNUM und stellen Sie sicher, dass der Index verwendet wird:

SELECT  *
FROM    (
        SELECT  /*+ INDEX_ASC(t index_on_column) NOPARALLEL_INDEX(t index_on_column) */
                t.*, ROWNUM AS rn
        FROM    table t
        ORDER BY
                column
        )
WHERE rn >= :start
      AND rownum <= :end - :start + 1

Diese Abfrage wird verwenden COUNT STOPKEY

Auch entweder sicherstellen, dass Sie column nicht NULL sein kann, oder WHERE column IS NOT NULL Bedingung hinzuzufügen.

Ansonsten kann der Index nicht verwendet werden, um alle Werte abgerufen werden.

Beachten Sie, dass Sie nicht ROWNUM BETWEEN :start and :end ohne Unterabfrage verwenden können.

ist ROWNUM immer zuletzt zugewiesen und Karomuster letzte, das ist viel ROWNUM ist immer kommen, um ohne Lücken.

Wenn Sie ROWNUM BETWEEN 10 and 20 verwenden, die erste Zeile, dass satisifies alle anderen Bedingungen wird ein Kandidat für die Rückkehr werden, vorübergehend mit ROWNUM = 1 zugeordnet und nicht den Test der ROWNUM BETWEEN 10 AND 20.

Dann wird die nächste Zeile wird mit ROWNUM = 1 und scheitert, etc., so schließlich ein Kandidat, zugewiesen wird, werden keine Zeilen überhaupt zurückgegeben werden.

Dies sollte, indem ROWNUM die in die Unterabfrage bearbeitet werden um.

Andere Tipps

Sieht aus wie eine Paginierung Abfrage zu mir.

Von diesem AskTom Artikel (etwa 90% unten auf der Seite):

Sie müssen durch etwas bestellen einzigartig für diese Paginierung Abfragen, so dass ROW_NUMBER jedes Mal deterministisch zu den Zeilen zugeordnet ist.

Auch Ihre Fragen sind nicht annähernd der gleichen so bin ich nicht sicher, was der Nutzen die Kosten von einem zum anderen zu vergleichen ist.

Ist Ihre ORDER BY Spalte indiziert? Wenn nicht, das ist ein guter Anfang.

Ein Teil des Problems ist, wie groß der ‚Start‘ bis ‚Ende‘ Spanne ist und wo sie ‚live‘. Sagen Sie bitte eine Million Zeilen in der Tabelle, und Sie wollen Zeilen 567.890 bis 567.900 dann werden Sie mit der Tatsache leben müssen, dass es durch die gesamte Tabelle zu gehen brauchen wird, sortiert ziemlich all das von id, und herauszufinden, welche Zeilen in diesen Bereich fallen.

Kurz gesagt, das ist eine Menge Arbeit, weshalb die Optimierer es hohe Kosten verursacht.

Es ist auch nicht etwas, ein Index mit viel helfen kann. Ein Index würde den Auftrag geben, sondern bestenfalls, das gibt Sie irgendwo anfangen und dann immer wieder zu lesen Sie weiter, bis Sie auf den Eintrag 567900. erhalten.

Wenn Sie Ihre Endbenutzer 10 Elemente gleichzeitig angezeigt wird, kann es tatsächlich wert sein, um die Top-100 von der DB greifen, dann mit der App Pause, dass 100 in zehn Stücke schneiden.

mehr Zeit mit dem PLAN-Tool EXPLAIN verbringen. Wenn Sie eine Tabelle SCAN sehen müssen Sie Ihre Abfrage ändern.

Ihre Anfrage macht wenig Sinn für mich. Abfragt über einen ROWID scheint wie Ärger bringen. Es gibt keine relationalen Daten in dieser Abfrage. Ist es die echte Abfrage, die Sie Probleme mit mit oder ein Beispiel, das Sie Ihr Problem aus bis zu veranschaulichen?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top