Почему это происходит?
Рассмотрим этот пример:
Project.objects.filter(body__icontains='x').count()
Это будет переведено в этот запрос (PostgreSQL):
SELECT COUNT(*) AS res
FROM project
WHERE UPPER(project.body::text) LIKE UPPER('%x%')
Если Есть много записей, это будет очень медленно. Как предложил @bruno - попытайтесь найти способ ее оптимизации (это может зависеть от вашей СУБД).
Классическая нумерация страниц в Django реализована с помощью операторов limit и offset SQL. В результате:
COUNT - (Время выполнения: 10,7 с)
OFFSET X - БД должна прочитать X записей с диска после соответствующей сортировки; Неверный список элементов, если новый элемент был вставлен в уже запрошенную страницу.
Обычно счетчик хэшируется, и когда добавляются новые записи, мы просто делаем обновления. OFFSET довольно сложно оптимизировать (кэширование?).
Есть ли лучшие решения?
KEYSET нумерация страниц, алгоритм следующий:
- Мы помним идентификаторы первого
FIRST_TIMESTAMP
и последнего LAST_TIMESTAMP
элемента на странице, например, это может быть дата публикации. - Чтобы получить следующую страницу, мы используем конструкцию:
WHERE table.date > LAST_TIMESTAMP ORDER_BY date ASC LIMIT <PAGE SIZE>
Преимущества:
- Работает намного быстрее на больших наборах запросов.
- Корректно обрабатывает изменения на предыдущих страницах при добавлении новых элементов , Есть несколько реализаций для Django.
Недостатки:
- Невозможно переключиться на случайную страницу, без предварительной загрузки данных, поэтому она подходит только для бесконечной прокрутки.
Так что, если это ваш случай, вы можете значительно ускорить нумерацию страниц.