Oracle SELECT TOP 10 Datensätze

Ich habe ein großes Problem mit einer SQL-Anweisung in Oracle. Ich möchte die TOP 10 Datensätze, geordnet nach STORAGE_DB, die nicht in einer Liste aus einer anderen Select-Anweisung sind, auswählen.

Diese Anweisung funktioniert gut für alle Datensätze:

SELECT DISTINCT 
  APP_ID, 
  NAME, 
  STORAGE_GB, 
  HISTORY_CREATED, 
  TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE  
  FROM HISTORY WHERE 
      STORAGE_GB IS NOT NULL AND 
        APP_ID NOT IN (SELECT APP_ID
                       FROM HISTORY
                        WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') = '06.02.2009') 

Aber wenn ich Folgendes hinzufüge

AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC

bekomme ich eine Art von "random" Records. Ich denke, weil das Limit vor der Bestellung in Kraft tritt.

Hat jemand eine gute Lösung? Das andere Problem: Diese Abfrage ist wirklich langsam (10k+ Datensätze)

Lösung

Sie müssen Ihre aktuelle Abfrage in eine Unterabfrage wie unten setzen:


SELECT * FROM (
  SELECT DISTINCT 
  APP_ID, 
  NAME, 
  STORAGE_GB, 
  HISTORY_CREATED, 
  TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE  
  FROM HISTORY WHERE 
    STORAGE_GB IS NOT NULL AND 
      APP_ID NOT IN (SELECT APP_ID FROM HISTORY WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') ='06.02.2009')
  ORDER BY STORAGE_GB DESC )
WHERE ROWNUM 
Kommentare (4)

Was die schlechte Leistung anbelangt, so gibt es eine ganze Reihe von Gründen, die dafür verantwortlich sein könnten, und das sollte wirklich eine separate Frage sein. Es gibt jedoch eine offensichtliche Sache, die ein Problem sein könnte:

WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') = '06.02.2009') 

Wenn es sich bei HISTORY_DATE wirklich um eine Datumsspalte handelt und diese einen Index hat, dann wird diese Umschreibung besser funktionieren:

WHERE HISTORY_DATE = TO_DATE ('06.02.2009', 'DD.MM.YYYY')  

Das liegt daran, dass eine Datentypkonvertierung die Verwendung eines B-Tree-Indexes deaktiviert.

Kommentare (0)

Sie erhalten eine scheinbar zufällige Menge, da ROWNUM vor ORDER BY angewendet wird. Ihre Abfrage nimmt also die ersten zehn Zeilen und sortiert sie.0 Um die zehn besten Gehälter auszuwählen, sollten Sie eine analytische Funktion in einer Unterabfrage verwenden und diese dann filtern:


 select * from 
     (select empno,
             ename,
             sal,
             row_number() over(order by sal desc nulls last) rnm
    from emp) 
 where rnm
Kommentare (0)