如何有效地分页超过1000万条记录

时间:2020-10-01 17:57:43

标签: mysql performance pagination cursor offset

我需要对MySQL上托管的超过3000万用户进行分页。我每页显示15个用户,但速度很慢。我的目标是访问任何随机页面并在几毫秒内加载它。

开始时,我在MySQL中使用offset方法,但是正如我所说的,它相当慢(肯定是个坏主意)。然后我搬到了ElasticSearch,但是您仍然有一些窗口限制,因此受到限制。在那之后,我一直在检查“ cursor”方法之类的不同方法,但是我无法访问任何随机页面。例如,我们从第一页开始,有100000页,我想访问第4782页,并在几毫秒内加载它。使用cursor方法,我只能访问下一个&&上一页,而“ scroll”方法无法满足我的实际需求。

我的用户ID不仅仅按ID排序,因此我不能将其用作定界符。已经考虑过Late row lookups

我不介意将所有数据移动到新的数据库中(但是会找到不同的解决方案)。亚马逊在这里做得很好(https://www.amazon.com/review/top-reviewers

使用偏移量查询:

SELECT users.* from users
WHERE users.country = 'DE'
ORDER BY users.posts_count DESC, users.id DESC
LIMIT 15 OFFSET 473

PD:我的用户列表几乎是实时的,因此每小时都在变化。

有什么想法吗?非常感谢!

2 个答案:

答案 0 :(得分:1)

“访问第4782页”-用例是什么? “分页”仅对几页有用,也许几十页,但没有几千页。

[下一页],[上一页],[第一],[最后]很有用。但是,如果您要使用随机探针,则将其称为[Random]探针,而不是“ 4782页”。

OFFSET效率低下。这是替代方案的讨论:http://mysql.rjweb.org/doc.php/pagination

同时添加INDEX(country, posts_count, id)

答案 1 :(得分:0)

使用Elasticsearch实现此目的的一种方法是向每个记录添加一个线性增加的字段(例如sort_field)(如果线性增加,则使用ID字段)。第一个记录的字段的值为1,第二个字段的值为2,第三个字段的值为3,等等...

然后,如果您以升序模式按该字段排序,则可以使用search_after feature来直接访问任何记录。

例如,如果您需要访问第4782页(即记录71730及以下),则可以这样实现:

POST my-index/_search 
{
  "size": 15,                      <--- the page size
  "sort": [
    {
      "sort_field": "asc"          <--- properly ordering the records
    }
  ],
  "search_after": [ 71730 ]        <--- direct access to the desired record/page
}

在某些情况下,还可以利用index sorting功能使排序更快。

注意:深度分页不是为Elasticsearch构建的。上面的解决方案有效,但根据您的情况可能会有一些缺点(请参阅评论)。对于您需要做的事情,它可能不是最好的可用技术。