Question

J'ai actuellement une implémentation de will_paginate qui utilise la méthode paginate_by_sql pour générer la collection à paginer. Nous avons une requête personnalisée pour total_entries qui est très compliquée et alourdit considérablement notre base de données. Par conséquent, nous aimerions couper le nombre total d'entrées de la pagination.

En d’autres termes, au lieu de l’affichage de pagination typique de «précédent 1 [2] 3 4 5 suivant», nous aimerions simplement un bouton «suivant - précédent». Mais nous devons savoir quelques choses.

  1. Affiche-t-on le lien précédent? Ceci ne se produira évidemment que si les enregistrements existants avant ceux affichés dans la sélection actuelle
  2. Affiche-t-on le lien suivant? Ceci ne sera pas affiché si le dernier enregistrement de la collection est affiché
De la / p>
  

Une requête pour compter les lignes sera   être généré automatiquement si vous   ne pas fournir: total_entries. Si vous   rencontrer des problèmes avec cette   SQL généré, vous voudrez peut-être   effectuer le compte manuellement dans votre   application.

La situation idéale est donc la suivante.

  • Supprimez le nombre total d'entrées car cela entraîne une charge excessive sur la base de données
  • Afficher 50 enregistrements à la fois avec une semi-pagination en utilisant uniquement les boutons suivants / précédents pour naviguer et ne nécessitant pas l'affichage de tous les numéros de page disponibles
  • Afficher uniquement le bouton suivant et le bouton précédent en conséquence

Quelqu'un a-t-il déjà travaillé sur un problème similaire ou a-t-il une solution au problème?

Était-ce utile?

La solution

Il y a de nombreuses occasions où will_paginate calcule vraiment le nombre d'entrées, en particulier si des jointures impliquent de confondre le générateur de décompte SQL.

Si tout ce dont vous avez besoin est une simple méthode prev / next, il vous suffit d'essayer d'extraire N + 1 entrées de la base de données, et si vous n'obtenez que N ou moins que ce que vous êtes à la dernière page.

Par exemple:

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

Vous pouvez facilement encapsuler ceci dans un module pouvant être inclus dans les différents modèles qui le nécessitent ou créer une extension de contrôleur.

J'ai constaté que cela fonctionnait nettement mieux que la méthode will_paginate par défaut.

Le seul problème de performances est une limitation de MySQL qui peut poser problème en fonction de la taille de vos tables.

Pour quelque raison que ce soit, le temps nécessaire pour effectuer une requête avec une petite limite dans MySQL est proportionnel à OFFSET. En effet, le moteur de base de données lit toutes les lignes menant à la valeur de décalage particulière, puis renvoie les lignes suivantes du nombre LIMIT, sans les avancer comme prévu.

Pour les grands ensembles de données, où les valeurs OFFSET se situent dans la plage plus de 100 000, il est possible que les performances se dégradent considérablement. Cela va se traduire par le fait que le chargement de la page 1 est très rapide, que la page 1000 est un peu lente, mais que la page 2000 est extrêmement lente.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top