Oracle Select Top 10 Records
سؤال
لدي مشكلة كبيرة مع بيان SQL في Oracle. أرغب في تحديد أفضل 10 سجلات تم طلبها بواسطة Storage_DB والتي ليست في قائمة من عبارة تحديد أخرى.
هذا واحد يعمل بشكل جيد لجميع السجلات:
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
ينطبق أوراكل رونوم إلى النتيجة بعد إرجاعها.
تحتاج إلى تصفية النتيجة بعد إرجاعها ، لذلك مطلوب مسمة فرعية. تستطيع ايضا استخذام مرتبة() وظيفة للحصول على نتائج Top-N.
للأداء حاول استخدام NOT EXISTS
بدلاً من NOT IN
. يرى هذه للمزيد من.
نصائح أخرى
إذا كنت تستخدم Oracle 12C ، استخدم:
جلبها التالي ن الصفوف فقط
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
مزيد من المعلومات: http://docs.oracle.com/javadb/10.5.3.0/ref/rrefsqljoffsetfetch.html
فيما يتعلق بالأداء الضعيف ، هناك أي عدد من الأشياء التي يمكن أن يكون ، ويجب أن تكون حقًا سؤالًا منفصلًا. ومع ذلك ، هناك شيء واضح يمكن أن يكون مشكلة:
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.
محاولة
SELECT * FROM users FETCH NEXT 10 ROWS ONLY;
يمكنك الحصول على مجموعة عشوائية على ما يبدو لأنه يتم تطبيق Rownum قبل الطلب. لذا فإن استعلامك يأخذ الصفوف العشرة الأولى وفرزها.
select * from
(select empno,
ename,
sal,
row_number() over(order by sal desc nulls last) rnm
from emp)
where rnm<=10