Mám veľký problém s príkazom SQL v Oracle. Chcem vybrať TOP 10 záznamov zoradených podľa STORAGE_DB, ktoré nie sú v zozname z iného príkazu select.
Tento funguje dobre pre všetky záznamy:
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')
Ale keď pridávam
AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC
Dostávam nejaké "náhodné" Záznamy. Myslím si, že preto, lebo limit sa zavedie pred objednávkou.
Má niekto dobré riešenie? Ďalší problém: Tento dotaz je naozaj pomalý (10k+ záznamov)
Budete musieť dať svoj aktuálny dotaz do poddotazu, ako je uvedené nižšie:
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 aplikuje rownum na výsledok po jeho vrátení.
Výsledok potrebujete filtrovať po jeho vrátení, preto je potrebný poddotaz. Na získanie Top-N výsledkov môžete použiť aj funkciu RANK().
Kvôli výkonu skúste použiť NOT EXISTS
namiesto NOT IN
. Viac informácií nájdete v this.
Pokiaľ ide o slabý výkon, môže to byť spôsobené mnohými vecami a malo by to byť naozaj samostatnou otázkou. Existuje však jedna zjavná vec, ktorá by mohla byť problémom:
WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') = '06.02.2009')
Ak je HISTORY_DATE skutočne stĺpec s dátumom a ak má index, potom bude tento prepis výkonnejší:
WHERE HISTORY_DATE = TO_DATE ('06.02.2009', 'DD.MM.YYYY')
Je to preto, že konverzia dátového typu znemožňuje použitie indexu B-Tree.
Získate zrejme náhodnú množinu, pretože ROWNUM sa použije pred ORDER BY. Váš dotaz teda vyberie prvých desať riadkov a zoradí ich.0 Ak chcete vybrať desať najvyšších platov, mali by ste použiť analytickú funkciu v poddotazu a tú potom filtrovať:
select * from
(select empno,
ename,
sal,
row_number() over(order by sal desc nulls last) rnm
from emp)
where rnm<=10