Использование will_paginate без :total_entries для улучшения длинного запроса

StackOverflow https://stackoverflow.com/questions/1421806

Вопрос

У меня есть текущая реализация will_paginate будет инициализирован который использует paginate_by_sql - разбиение на страницы метод создания коллекции, подлежащей разбивке на страницы.У нас есть пользовательский запрос для всего входов это очень сложно и создает большую нагрузку на нашу базу данных.Поэтому мы хотели бы полностью исключить total_entries из разбивки на страницы.

Другими словами, вместо типичного отображения разбивки на страницы "предыдущий 1 [2] 3 4 5 следующий" нам просто нужна только кнопка "следующий - предыдущий".Но нам нужно знать несколько вещей.

  1. Показываем ли мы предыдущую ссылку?Конечно, это произойдет только в том случае, если записи, существующие до тех, которые отображаются в текущем выборе
  2. Показываем ли мы следующую ссылку?Это не было бы отображено, если бы отображалась последняя запись в коллекции

Из Документы

Запрос для подсчета строк будет сгенерирован автоматически, если вы не укажете :total_entries.Если у вас возникнут проблемы с этим сгенерированным SQL, вы можете захотеть выполнить подсчет вручную в своем приложении.

Таким образом, в конечном счете идеальной ситуацией является следующая.

  • Удалите счетчик total_entries, потому что это вызывает слишком большую нагрузку на базу данных
  • Одновременное отображение 50 записей с разделением на страницы, используя только кнопки next / previous для навигации и не требуя отображения всех доступных номеров страниц.
  • Отображайте только следующую кнопку и предыдущую кнопку соответственно

Кто-нибудь работал с подобной проблемой или у вас есть мысли по ее решению?

Это было полезно?

Решение

Есть много случаев, когда will_paginate выполняет действительно ужасную работу по вычислению количества записей, особенно если задействованы соединения, которые сбивают с толку SQL-генератор count.

Если все, что вам нужно, это простой предыдущий / следующий метод, то все, что вам нужно сделать, это попытаться извлечь N + 1 записи из базы данных, и если вы получите только N или меньше, чем на последней странице.

Например:

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

Вы можете легко инкапсулировать это в какой-нибудь модуль, который может быть включен в различные модели, требующие этого, или создать расширение контроллера.

Я обнаружил, что это работает значительно лучше, чем метод will_paginate по умолчанию.

Единственная проблема с производительностью - это ограничение MySQL, которое может быть проблемой в зависимости от размера ваших таблиц.

По какой-либо причине количество времени, необходимое для выполнения запроса с небольшим ограничением в MySQL, пропорционально СМЕЩЕНИЮ.По сути, компонент database engine считывает все строки, ведущие к определенному значению смещения, затем возвращает строки следующего предельного числа, не пропуская вперед, как можно было бы ожидать.

Для больших наборов данных, где у вас есть значения СМЕЩЕНИЯ в диапазоне от 100 000 плюс, вы можете обнаружить значительное снижение производительности.Это будет проявляться в том, что загрузка страницы 1 происходит очень быстро, страница 1000 - несколько медленно, но страница 2000 - чрезвычайно медленно.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top