Oracle SELECT TOP 10 kayıtları


144

Oracle bir SQL deyimi ile büyük bir sorun var. STORAGE_DB tarafından sipariş edilen ve başka bir select deyiminden bir listede olmayan TOP 10 kayıtlarını 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 çeşit "rasgele" Kayıt alıyorum. Sanırım sınır siparişten önce gerçekleşiyor.

Birinin iyi bir çözümü var mı? Diğer sorun: Bu sorgu gerçekten yavaş (10k + kayıt)



Yanıtlar:


199

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 .
Sonucu döndürüldükten sonra filtrelemeniz gerekir, bu nedenle bir alt sorgu gerekir. Top-N sonuçlarını almak için RANK () işlevini de kullanabilirsiniz .

Performans NOT EXISTSiçin yerine kullanmayı deneyin NOT IN. Bkz bu daha fazlası.


NOT EXISTS bu senaryoda çalışmıyor (geçersiz ilişkisel operatör) APP_ID NOT EXISTS (SELEC ...)
opHASnoNAME

3
Bazıları bunun insanları Oracle'a kapatmak için uygun olduğunu söyleyebilir.
MrBoJangles

2
FETCH NEXT N ROWS ONLYAşağıdaki cevabı kontrol edin .
Mohnish

@Padmarag: Böyle bir sorguda bir rownum ne zaman uygulanır - SomeTol'dan * seçin, burada someColumn = '123' ve rownum <= 3. [SomeTol'dan * Select * from someColumn = '123'] 'den sonuçları seçtikten sonra mı
Shirgill Farhan

55

Oracle 12c kullanıyorsanız, şunu kullanın:

FETCH SADECE N SIRA

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

Daha fazla bilgi: http://docs.oracle.com/javadb/10.5.3.0/ref/rrefsqljoffsetfetch.html


2
Bu diğer cevaba göre altın
aswzen


1
Bu yanıtı 100 yukarı vermek istiyorum! Ama ne yazık ki, sadece bir tane ödül vereceğim. Bir tane!
Eidylon

23

Kötü performans ile ilgili olarak, olabilecek çok sayıda şey vardır ve gerçekten ayrı bir soru olmalıdır. Ancak, bir 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 dizini varsa, bu yeniden yazma daha iyi performans gösterir:

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

Bunun nedeni, bir veri türü dönüştürmesinin B-Tree dizininin kullanımını devre dışı bırakmasıdır.


22

Deneyin

SELECT * FROM users FETCH NEXT 10 ROWS ONLY;

11

Görünüşe göre rastgele bir küme alırsınız çünkü ROWNUM ORDER BY'dan önce uygulanır. Böylece, sorgunuz ilk on satırı alır ve sıralar.

 select * from 
     (select empno,
             ename,
             sal,
             row_number() over(order by sal desc nulls last) rnm
    from emp) 
 where rnm<=10
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.