frankban / django-endless-pagination

This project is deprecated: please use https://github.com/shtalinberg/django-el-pagination
MIT License
251 stars 108 forks source link

[SQL optimization] Use keyset pagination (a.k.a. seek method) #80

Open BertrandBordage opened 9 years ago

BertrandBordage commented 9 years ago

Current implementation uses QuerySet slicing, which translates into a LIMIT n OFFSET x in SQL.

The problem is that your database has to go through your entire table to select only a small quantity of rows. If your database contains thousands or millions of rows, this leads to far slower queries.

This can be solved using keyset pagination.

That would mean switching from qs[offset:limit] to qs.filter(**kwargs)[:limit] where kwargs is a dict created from the ORDER BY columns and their values in the previous page.

A Django implementation of this solution already exists. But it’s not using the ORM to discover which columns are ordering, and you can only order by one column, so it’s quite useless.

The columns in ORDER BY can be easily fetched using this:

q = qs.query
order_by = q.extra_order_by or (q.get_meta().ordering if q.default_ordering
                                else q.order_by) or []

Of course, the real challenge is to get data from the previous page. Unless we already asked for the previous page, we can’t get these data. In that "first query scenario", nothing special can be done, we have to use OFFSET. Otherwise, there are two solutions in my opinion: