Oracle ile sayfalama


98

Oracle'a olmak istediğim kadar aşina değilim. Yaklaşık 250 bin kaydım var ve bunları sayfa başına 100 görüntülemek istiyorum. Şu anda, bir veri bağdaştırıcısı ve veri kümesi kullanarak bir veri kümesine çeyrek milyon kaydın tümünü alan tek bir saklı yordamım ve depolanan işlemden elde edilen sonuçlarla ilgili veri bağdaştırıcısı.Fill (veri kümesi) yöntemim var. Parametre olarak geçirebileceğim tamsayı değerleri olarak "Sayfa Numarası" ve "Sayfa başına kayıt sayısı" varsa, sadece o bölümü geri almanın en iyi yolu ne olurdu. Diyelim ki, bir sayfa numarası olarak 10'u ve sayfa sayısı olarak 120'yi geçersem, seçme ifadesinden bana 1880'den 1200'e kadar verirdi ya da bunun gibi bir şey, kafamdaki matematiğim yanlış olabilir.

Bunu .NET ile C # ile yapıyorum, bunun önemli olmadığını düşündüm, eğer doğru SQL tarafında alabilirsem, o zaman havalı olmalıyım.

Güncelleme: Brian'ın önerisini kullanabildim ve harika çalışıyor. Biraz optimizasyon üzerinde çalışmak istiyorum, ancak sayfalar bir dakika yerine 4 ila 5 saniye içinde geliyor ve sayfalama kontrolüm yeni depolanan prosedürlerimle çok iyi bir şekilde bütünleşebildi.

Yanıtlar:


148

Bunun gibi bir şey işe yaramalı : Frans Bouma'nın Blogundan

SELECT * FROM
(
    SELECT a.*, rownum r__
    FROM
    (
        SELECT * FROM ORDERS WHERE CustomerID LIKE 'A%'
        ORDER BY OrderDate DESC, ShippingDate DESC
    ) a
    WHERE rownum < ((pageNumber * pageSize) + 1 )
)
WHERE r__ >= (((pageNumber-1) * pageSize) + 1)

4
Evet, Oracle'ın desteklediği 'yerleşik' bir sütundur, her zaman 1'den başlar ve her satır için artar. Dolayısıyla, bu kod parçacığında 1000 satırınız varsa, sıralama düzeni uygulanır ve ardından her satıra bir satır atanır. Dış seçimler, aradığınız 'sayfayı' sayfa boyutunuza göre bulmak için bu satır numaralarını kullanır.
Brian Schmitt

9
Bu güzel, ancak büyük seçimlerde korkunç derecede yavaş, sadece 0 - 1000 ve 500.000 - 501.000 arasında seçim yapma zamanının ne olacağını kontrol edin ... Bu tür bir seçme yapısı kullanıyordum şimdi bir geçici çözüm arıyorum.
newhouse

3
@ n3whous3 bunu deneyebilirsiniz - inf.unideb.hu/~gabora/pagination/results.html
jasonk

7
Neden iki WHEREile birleştirilemediğini merak ettim ANDve sonra şunu buldum: orafaq.com/wiki/ROWNUM
Mengdi Gao

1
Oracle sayfalandırması günümü mahvediyor.
Aetherus

136

Tom'a sayfalandırma ve çok, çok yararlı analitik işlevler hakkında soru sorun .

Bu, o sayfadan alıntıdır:

select * from (
    select /*+ first_rows(25) */
     object_id,object_name,
     row_number() over
    (order by object_id) rn
        from all_objects)
    where rn between :n and :m
        order by rn;

7
Bu aslında çok daha iyi bir uygulama, ancak o gönderide bulmak zor. Çok sayıda büyük sayfanız olduğunda, diğer yanıt da önceki sayfalardaki tüm satırların üzerinden geçmelidir. Karmaşık sorgularda bu, sonraki sayfaların önceki sayfalardan daha kötü performans gösterdiği anlamına gelir.
tallseth

@tallseth Haklısın. Onu o sayfada bulmak zor. Alıntı eklendi.
Chobicus

Sıranızı dinamik olarak değiştirmek istiyorsanız doğru cevap budur.
chakeda

76

Eksiksizlik adına, daha modern bir çözüm arayan kişiler için, Oracle 12c'de daha iyi sayfalama ve üst düzey kullanım dahil olmak üzere bazı yeni özellikler var.

Çağrı

Sayfalama şuna benzer:

SELECT *
FROM user
ORDER BY first_name
OFFSET 5 ROWS FETCH NEXT 10 ROWS ONLY;

En İyi N Kayıt

En iyi kayıtları almak şu şekildedir:

SELECT *
FROM user
ORDER BY first_name
FETCH FIRST 5 ROWS ONLY

Yukarıdaki sorgu örneklerinin her ikisinin de ORDER BYyan tümceleri olduğuna dikkat edin . Yeni komutlar bunlara uyar ve sıralanan veriler üzerinde çalıştırılır.

FETCHVeya için iyi bir Oracle referans sayfası bulamadım, OFFSETancak bu sayfada bu yeni özelliklere harika bir genel bakış var.

Verim

@Wweicker'ın aşağıdaki yorumlarda işaret ettiği gibi, performans 12c'deki yeni sözdizimiyle ilgili bir sorundur. Oracle'ın o zamandan beri geliştirip geliştirmediğini test etmek için bir 18c kopyasına sahip değildim.

İlginçtir ki, yeni yöntem için masamdaki sorguları (113 milyon + satır) ilk kez çalıştırdığımda gerçek sonuçlarım biraz daha hızlı döndü:

  • Yeni yöntem: 0,013 saniye.
  • Eski yöntem: 0.107 saniye.

Bununla birlikte, @wweicker'ın da belirttiği gibi, açıklama planı yeni yöntem için çok daha kötü görünüyor:

  • Yeni yöntem maliyeti: 300.110
  • Eski yöntem maliyeti: 30

Yeni sözdizimi, sütunumdaki dizinin tam olarak taranmasına neden oldu, bu da maliyetin tamamıydı. Şanslar, dizine eklenmemiş verileri sınırlarken işler çok daha kötüye gidiyor.

Önceki veri kümesine dizine eklenmemiş tek bir sütun eklerken bir göz atalım:

  • Yeni yöntem süresi / maliyeti: 189,55 saniye / 998.908
  • Eski yöntem süresi / maliyeti: 1.973 saniye / 256

Özet: Oracle bu işlemi geliştirene kadar dikkatli kullanın. Çalışacak bir dizininiz varsa, belki yeni yöntemi kullanmaktan kurtulabilirsiniz.

Umarım yakında oynayabileceğim bir 18c kopyası olur ve güncelleyebilirim


Bu, 12c kullanıcıları için harika bir cevap
Lalji Gajera

1
Sözdizimi daha temiz, ancak performans daha kötü ( dba-presents.com/index.php/databases/oracle/… )
wweicker

Bilmekte fayda var, teşekkürler @wweicker. Umarım performans yakında Oracle tarafından düzelir; Oracle'ı bilmek, uzak bir umut olabilir!
JoelC

Sözdizimi yenidir ve normal ROW_NUMBER / RANK çağrılarına dönüştürülür. İlgili Sipariş verdikten sonra bir Oracle sorgusu tarafından döndürülen satır sayısını nasıl sınırlayabilirim?
Lukasz Szozda

@JoelC fikrinizde herhangi bir değişiklik oldu mu?
Ryan

11

Sadece cevapları ve yorumları özetlemek istiyorum. Sayfalandırma yapmanın birkaç yolu vardır.

Oracle 12c'den önce OFFSET / FETCH işlevi yoktu, bu nedenle @jasonk'un önerdiği teknik incelemeye bir göz atın . Avantaj ve dezavantajların ayrıntılı açıklamasını içeren farklı yöntemler hakkında bulduğum en eksiksiz makale. Bunları buraya kopyalayıp yapıştırmak çok zaman alır, bu yüzden yapmayacağım.

Ayrıca, jooq yaratıcılarından oracle ve diğer veritabanları sayfalandırma ile ilgili bazı genel uyarıları açıklayan iyi bir makale var. jooq'un blog gönderisi

İyi haber, oracle 12c'den beri yeni bir OFFSET / FETCH işlevine sahibiz. OracleMagazine 12c yeni özellikler . Lütfen "İlk N Sorgu ve Sayfalandırma" bölümüne bakın

Aşağıdaki beyanı yayınlayarak oracle sürümünüzü kontrol edebilirsiniz

SELECT * FROM V$VERSION

7

Takip etmeyi dene:

SELECT *
FROM
  (SELECT FIELDA,
    FIELDB,
    FIELDC,
    ROW_NUMBER() OVER (ORDER BY FIELDC) R
  FROM TABLE_NAME
  WHERE FIELDA = 10
  )
WHERE R >= 10
AND R   <= 15;

[tecnicume] aracılığıyla


0

Projemde kullanılan Oracle 12c ve java . Sayfalama kodu şuna benzer:

 public public List<Map<String, Object>> getAllProductOfferWithPagination(int pageNo, int pageElementSize, Long productOfferId, String productOfferName) {
    try {

        if(pageNo==1){
            //do nothing
        } else{
            pageNo=(pageNo-1)*pageElementSize+1;
        }
        System.out.println("algo pageNo: " + pageNo +"  pageElementSize: "+ pageElementSize+"  productOfferId: "+ productOfferId+"  productOfferName: "+ productOfferName);

        String sql = "SELECT * FROM ( SELECT * FROM product_offer po WHERE po.deleted=0 AND (po.product_offer_id=? OR po.product_offer_name LIKE ? )" +
             " ORDER BY po.PRODUCT_OFFER_ID asc) foo OFFSET ? ROWS FETCH NEXT ? ROWS ONLY ";

       return jdbcTemplate.queryForList(sql,new Object[] {productOfferId,"%"+productOfferName+"%",pageNo-1, pageElementSize});

    } catch (Exception e) {
        System.out.println(e);
        e.printStackTrace();
        return null;
    }
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.