2009-09-14 10 views
5

ho un'implementazione corrente di will_paginate che utilizza il metodo di paginate_by_sqlper costruire la raccolta deve essere impaginato. Abbiamo una query personalizzata per total_entries che è molto complicato e mette un grosso carico sul nostro DB. Pertanto vorremmo tagliare total_entries dall'impaginazione del tutto.Utilizzando will_paginate senza: total_entries per migliorare una lunga interrogazione

In altre parole, invece del tipico display di impaginazione di "precedente 1 [2] 3 4 5 successivo", vorremmo semplicemente un pulsante "next - previous" solo. Ma abbiamo bisogno di sapere alcune cose.

  1. Visualizziamo il collegamento precedente? Ciò si verifica naturalmente solo se i record esistenti prima di quelli visualizzati nella selezione corrente
  2. Visualizziamo il collegamento successivo? Questo non sarebbe essere visualizzato se viene visualizzato l'ultimo record nella raccolta

Dal docs

Una query per le righe conteggio verrà automaticamente generato se non si fornisce: total_entries. Se si verificano problemi con questo SQL generato da , è possibile eseguire manualmente il conteggio nell'applicazione .

Quindi, in definitiva, la situazione ideale è la seguente.

  • Togliere il conteggio dei total_entries perché sta causando carico eccessivo sul database
  • Mostra 50 record alla volta con semi-impaginazione utilizzando solo pulsanti avanti/indietro per navigare e non aver bisogno di visualizzare tutti i numeri di pagina disponibili
  • visualizzare solo il pulsante Avanti e il pulsante precedente di conseguenza

qualcuno ha lavorato con un problema simile o di avere pensieri su una risoluzione?

risposta

13

Ci sono molte occasioni in cui will_paginate fa un lavoro davvero pessimo per calcolare il numero di voci, specialmente se ci sono join coinvolti che confondono il generatore di conteggi SQL.

Se tutto ciò che serve è un semplice metodo prev/next, allora tutto ciò che devi fare è tentare di recuperare le voci N + 1 dal database e se ottieni solo N o meno di quello che sei nell'ultima pagina .

Ad esempio:

per_page = 10 
page = 2 

@entries = Thing.with_some_scope.find(:all, :limit => per_page + 1, :offset => (page - 1) * per_page) 

@next_page = @entries.slice!(per_page, 1) 
@prev_page = page > 1 

Si può facilmente incapsulare questo in qualche modulo che può essere incluso nei vari modelli che lo richiedono, o fare un estensione del controller.

Ho trovato che questo funziona significativamente meglio del metodo predefinito will_paginate.

L'unico problema di prestazioni è una limitazione di MySQL che potrebbe essere un problema a seconda delle dimensioni delle tabelle.

Per qualsiasi motivo, il tempo necessario per eseguire una query con un LIMIT piccolo in MySQL è proporzionale allo OFFSET. In effetti, il motore del database legge tutte le righe che portano al particolare valore di offset, quindi restituisce le righe del numero LIMIT successivo, non saltando come ci si aspetterebbe.

Per i set di dati di grandi dimensioni, in cui si hanno valori di OFFSET nell'intervallo 100.000 più, è possibile che le prestazioni si degradino in modo significativo. Come questo si manifesterà è che il caricamento della pagina 1 è molto veloce, la pagina 1000 è un po 'lenta, ma la pagina 2000 è estremamente lenta.

+0

Grazie per l'idea. Ho intenzione di hackerare e vedere cosa posso inventare. Ho alcune lunghe query SQL personalizzate da gestire, ma penso che dovrei essere in grado di farle funzionare in soluzione e avere un'idea di come saranno le prestazioni. Grazie! – mwilliams

+0

Grazie per la risposta. Bello e semplicistico e ho guardato ben oltre una soluzione così semplice. La maggior parte della mia implementazione è a posto e sembra già molto meglio. Anche se sto avendo problemi con i pulsanti next/previous, ma lo prendo abbastanza presto. Grazie ancora! – mwilliams

Problemi correlati