2009-09-14 7 views
5

Tengo una implementación actual de will_paginate que utiliza el método de paginate_by_sql para construir la colección para ser paginado. Tenemos una consulta personalizada para total_entries que es muy complicada y pone una gran carga en nuestro DB. Por lo tanto, nos gustaría cortar totales_entradas de la paginación por completo.will_paginate sin: total_entries para mejorar una consulta larga

En otras palabras, en lugar de la típica visualización de paginación de 'anterior 1 [2] 3 4 5 siguiente', simplemente nos gustaría un botón 'siguiente - anterior' solamente. Pero necesitamos saber algunas cosas.

  1. ¿Mostramos el enlace precedente? Esto solo ocurriría por supuesto si los registros existentes antes de los que se muestran en la selección actual
  2. ¿Mostramos el siguiente enlace? Esto no se mostrará si el último registro de la colección se muestra

Desde el docs

se se generará automáticamente una consulta para contar las filas si no se proporciona : total_entries. Si tiene problemas de experiencia con este SQL generado , es posible que desee realizar el recuento manualmente en la aplicación .

Así que en última instancia, la situación ideal es la siguiente.

  • Eliminar cuentan los total_entries porque está causando demasiada carga en la base de datos
  • Mostrar 50 registros a la vez con semi-paginación utilizando únicamente siguiente/botones anterior de navegar y no tener que visualizar todos los números de página disponibles
  • Sólo mostrar el botón siguiente y en consecuencia botón anterior

alguien ha trabajado con un problema similar o tiene pensamientos sobre una resolución?

Respuesta

13

Hay muchas ocasiones en que will_paginate hace un trabajo realmente horrible al calcular el número de entradas, especialmente si hay combinaciones involucradas que confunden el generador de cuentas SQL.

Si todo lo que necesita es un simple método anterior/siguiente, entonces todo lo que necesita hacer es intentar recuperar N + 1 entradas de la base de datos, y si solo obtiene N o menos de lo que está en la última página .

Por ejemplo:

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 

Puede encapsular fácilmente esto en algún módulo que puede ser incluido en los diversos modelos que lo requieran, o hacer una extensión de controlador.

He encontrado que esto funciona significativamente mejor que el método predeterminado de will_paginate.

El único problema de rendimiento es una limitación de MySQL que puede ser un problema según el tamaño de las tablas.

Por alguna razón, la cantidad de tiempo que lleva realizar una consulta con un pequeño LÍMITE en MySQL es proporcional al DESPLAZAMIENTO. En efecto, el motor de la base de datos lee todas las filas que conducen al valor de compensación particular, luego devuelve las siguientes filas de números de LÍMITE, sin omitir el avance como es de esperar.

Para conjuntos de datos grandes, donde tiene valores de DESPLAZAMIENTO en el rango de 100.000 más, es posible que el rendimiento disminuya significativamente. Cómo se manifestará esto es que cargar la página 1 es muy rápido, la página 1000 es algo lenta, pero la página 2000 es extremadamente lenta.

+0

Gracias por la idea. Voy a piratear y ver qué puedo inventar. Tengo que lidiar con algunas largas consultas SQL personalizadas, pero creo que debería poder ponerlas a trabajar en la solución y tener una idea de cómo será el rendimiento. ¡Gracias! – mwilliams

+0

Gracias por responder. Agradable y simplista, y miré mucho más allá de una solución tan simple. La mayor parte de mi implementación está en su lugar y parece mucho mejor. Aunque estoy teniendo problemas con los botones siguiente/anterior, pero lo haré lo suficientemente rápido. ¡Gracias de nuevo! – mwilliams

Cuestiones relacionadas