Registros do Oracle SELECT TOP 10

Eu tenho um grande problema com uma Declaração SQL no Oracle. Eu quero selecionar os TOP 10 Records ordenados por STORAGE_DB que estão't em uma lista de uma outra instrução selecionada.

Este aqui funciona bem para todos os registos:

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') 

Mas quando eu estou a adicionar

AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC

I'estou recebendo algum tipo de "aleatório" Registros. Acho que porque o limite é anterior ao pedido.

Alguém tem uma boa solução? O outro problema: Esta consulta é muito lenta (10k+ registos).

Solução

Você'precisará colocar sua consulta atual na subconsulta como abaixo :


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 
Comentários (4)

No que diz respeito ao mau desempenho, há uma série de coisas que poderiam ser, e realmente deveria ser uma questão à parte. No entanto, há uma coisa óbvia que pode ser um problema:

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

Se HISTORY_DATE é realmente uma coluna de datas e se tiver um índice, então esta reescrita terá um melhor desempenho:

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

Isto porque uma conversão tipo datatype desabilita o uso de um índice B-Tree.

Comentários (0)

Você recebe um conjunto aparentemente aleatório porque o ROWNUM é aplicado antes do ORDER BY. Então sua consulta pega as primeiras dez linhas e as ordena.0 Para selecionar os dez salários mais altos você deve usar uma função analítica em uma subconsulta, depois filtrar isso:


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