Έχω ένα μεγάλο πρόβλημα με μια δήλωση SQL στην Oracle. Θέλω να επιλέξω τις TOP 10 εγγραφές ταξινομημένες κατά STORAGE_DB οι οποίες δεν βρίσκονται σε μια λίστα από μια άλλη δήλωση select.
Αυτή η εντολή λειτουργεί καλά για όλες τις εγγραφές:
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')
Αλλά όταν προσθέτω
AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC
Παίρνω κάποιο είδος "τυχαίων" εγγραφών. Νομίζω ότι επειδή το όριο παίρνει θέση πριν από την παραγγελία.
Μήπως κάποιος έχει μια καλή λύση; Το άλλο πρόβλημα: Αυτό το ερώτημα είναι πραγματικά αργό (10k+ εγγραφές).
Θα πρέπει να βάλετε το τρέχον ερώτημά σας σε υποερώτημα όπως παρακάτω :
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 εφαρμόζει το rownum στο αποτέλεσμα μετά την επιστροφή του.
Πρέπει να φιλτράρετε το αποτέλεσμα μετά την επιστροφή του, οπότε απαιτείται ένα υποερώτημα. Μπορείτε επίσης να χρησιμοποιήσετε τη συνάρτηση RANK() για να λάβετε τα Top-N αποτελέσματα.
<br>,
Για λόγους απόδοσης δοκιμάστε να χρησιμοποιήσετε το NOT EXISTS
στη θέση του NOT IN
. Δείτε this για περισσότερες πληροφορίες.
Όσον αφορά τις χαμηλές επιδόσεις, υπάρχουν πολλά πράγματα που θα μπορούσαν να οφείλονται σε αυτές και θα έπρεπε να αποτελούν ξεχωριστή ερώτηση. Ωστόσο, υπάρχει ένα προφανές πράγμα που θα μπορούσε να αποτελεί πρόβλημα:
WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') = '06.02.2009')
Αν η HISTORY_DATE είναι πραγματικά μια στήλη ημερομηνίας και αν έχει δείκτη τότε αυτή η επανεγγραφή θα έχει καλύτερη απόδοση:
WHERE HISTORY_DATE = TO_DATE ('06.02.2009', 'DD.MM.YYYY')
Αυτό συμβαίνει επειδή μια μετατροπή τύπου δεδομένων απενεργοποιεί τη χρήση ενός ευρετηρίου B-Tree.
Παίρνετε ένα προφανώς τυχαίο σύνολο επειδή η ROWNUM εφαρμόζεται πριν από την ORDER BY. Έτσι, το ερώτημά σας παίρνει τις δέκα πρώτες γραμμές και τις ταξινομεί. 0 Για να επιλέξετε τους δέκα πρώτους μισθούς θα πρέπει να χρησιμοποιήσετε μια αναλυτική συνάρτηση σε ένα υποερώτημα και στη συνέχεια να φιλτράρετε αυτό:
select * from
(select empno,
ename,
sal,
row_number() over(order by sal desc nulls last) rnm
from emp)
where rnm<=10