Pergunta

Tenho um grande problema com uma declaração SQL no Oracle. Quero selecionar os 10 principais registros encomendados pelo Storage_DB, que não estão em uma lista de outra instrução SELECT.

Este funciona bem para todos os registros:

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 estou adicionando

AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC

Estou recebendo algum tipo de registros "aleatórios". Eu acho que porque o limite leva em vigor antes da ordem.

Alguém tem uma boa solução? O outro problema: esta consulta é realmente lenta (10k+ registros)

Foi útil?

Solução

Você precisará colocar sua consulta atual em subconsiva 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 <= 10

Oracle se aplica ROWNUM para o resultado depois de devolvido.
Você precisa filtrar o resultado após o retorno, para que seja necessária uma subconsulta. Você também pode usar CLASSIFICAÇÃO() Função para obter resultados de Top-N.

Para desempenho de desempenho usar NOT EXISTS no lugar de NOT IN. Ver isto para mais.

Outras dicas

Se você estiver usando o Oracle 12C, use:

Buscar a seguir N Apenas linhas

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
FETCH NEXT 10 ROWS ONLY

Mais informações: http://docs.oracle.com/javadb/10.5.3.0/ref/rrefsqljoffsetfetch.html

Com relação ao mau desempenho, há várias coisas que poderia ser, e realmente deve ser uma pergunta separada. 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 for uma coluna de data e se tiver um índice, esta reescrita terá um desempenho melhor:

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

Isso ocorre porque uma conversão de dados de dados desativa o uso de um índice B-Tree.

tentar

SELECT * FROM users FETCH NEXT 10 ROWS ONLY;

Você obtém um conjunto aparentemente aleatório porque o ROWNUM é aplicado antes da ordem. Portanto, sua consulta pega as dez primeiras linhas e as classifica.0 Para selecionar os dez principais salários que você deve usar uma função analítica em uma subconsulta e filtre isso:

 select * from 
     (select empno,
             ename,
             sal,
             row_number() over(order by sal desc nulls last) rnm
    from emp) 
 where rnm<=10
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top