Oracle'da bir SQL Deyimi ile ilgili büyük bir sorunum var. Başka bir select deyiminden bir listede olmayan STORAGE_DB tarafından sıralanan TOP 10 Kaydı seçmek istiyorum.
Bu, tüm kayıtlar için iyi çalışır:
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')
Ama eklediğimde
AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC
Bir tür "rastgele" Kayıt alıyorum. Sanırım limit siparişten önce gerçekleştiği için.
İyi bir çözümü olan var mı? Diğer sorun: Bu sorgu gerçekten çok yavaş (10k+ kayıt)
Mevcut sorgunuzu aşağıdaki gibi alt sorguya koymanız gerekir:
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, döndürüldükten sonra sonuca rownum uygular.
Döndürüldükten sonra sonucu filtrelemeniz gerekir, bu nedenle bir alt sorgu gereklidir. Top-N sonuçlarını almak için RANK() fonksiyonunu da kullanabilirsiniz.
Performans için NOT IN
yerine NOT EXISTS
kullanmayı deneyin. Daha fazlası için this'e bakın.
Düşük performansla ilgili olarak, bunun pek çok nedeni olabilir ve bu gerçekten ayrı bir soru olmalıdır. Ancak, sorun olabilecek bariz bir şey var:
WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') = '06.02.2009')
HISTORY_DATE gerçekten bir tarih sütunuysa ve bir dizine sahipse, bu yeniden yazma daha iyi performans gösterecektir:
WHERE HISTORY_DATE = TO_DATE ('06.02.2009', 'DD.MM.YYYY')
Bunun nedeni, bir veri türü dönüşümünün B-Ağacı dizininin kullanımını devre dışı bırakmasıdır.
ORDER BY'den önce ROWNUM uygulandığı için görünüşte rastgele bir küme elde edersiniz. Yani sorgunuz ilk on satırı alır ve bunları sıralar.0 İlk on maaşı seçmek için bir alt sorguda analitik bir işlev kullanmalı, ardından bunu filtrelemelisiniz:
select * from
(select empno,
ename,
sal,
row_number() over(order by sal desc nulls last) rnm
from emp)
where rnm<=10