Won*_*nka 7 mysql cursors select paging mysql-5.7
对于大型数据集,使用 an 进行分页OFFSET是众所周知的,并且不是最好的分页方式。更好的分页方式是使用游标,它只是行上的一个唯一标识符,因此我们知道从最后一个光标位置上次离开的位置继续分页的位置。
当涉及到一个自动递增id值的游标时,实现起来相当容易:
SELECT * FROM users
WHERE id <= %cursor // cursor is the auto incrementing id, ex. 100000
ORDER BY id DESC
LIMIT %limit
Run Code Online (Sandbox Code Playgroud)
我们不确定的是,如果不是自动递增id游标,游标的唯一唯一顺序标识符是表行上的uuid和created_at。
我们当然可以根据 查询uuid得到created_at,然后选择所有的users,<= created_at但问题是如果表中有多个相同created_at时间戳的实例users怎么办?知道如何users根据uuid/created_at游标组合查询表以确保我们获得正确的数据集(就像我们使用自动递增一样id)?再次,只有独特的领域是uuid因为created_at可能是重复的,但他们的组合是每行唯一的。
我会回答你的问题,但首先让我告诉你,我不明白你为什么要这样做。自动增量 ID 非常适合此任务。但同时使用时间戳列是正确的,因为依赖 id 进行排序是一种不好的做法。为什么?因为在某些情况下,其顺序可能不按时间顺序排列 - 例如,如果您使用 Galera 集群并且有故障转移。
要执行您要求的操作,首先创建此索引:
ALTER TABLE users
ADD INDEX idx_created_at_uuid (created_at, uuid);
Run Code Online (Sandbox Code Playgroud)
顺序列很重要。如果颠倒过来,索引就没有用了。
现在您只需要运行如下查询:
SELECT some_columns
FROM users
WHERE (created_at, uuid) < (x, y)
ORDER BY created_at DESC;
Run Code Online (Sandbox Code Playgroud)
uuid只是因为created_at不唯一才需要。上面的表达式使用称为行构造函数的语法。, unless these values are equal, in which case it compares 它很直观:它与created_at < x uuid y`相同and。
如果created_at不是索引中的第一列,MySQL 将必须读取所有行并将它们复制到临时表(可以在内存中或在磁盘上)以对它们进行排序。
如果您决定使用 id,只需保留上面的片段,但替换uuid为id.
编辑 11 月 22 日 16 日:WHERE 子句不正确。我修复了它并解释了语法。
WHERE created_at <= x
AND ( created_at < x OR uuid < y )
ORDER BY created_at DESC,
uuid DESC
Run Code Online (Sandbox Code Playgroud)
或这个等价物:
WHERE ( created_at < x
OR ( created_at = x AND uuid < y )
)
ORDER BY created_at DESC,
uuid DESC
Run Code Online (Sandbox Code Playgroud)
这种技术适用于任何一对列,其中第一个 ( created_at) 可能有重复,第二个是唯一的 (uuid或id)。
这是必需的:
INDEX(created_at, uuid)
Run Code Online (Sandbox Code Playgroud)
请注意, 的两个部分WHERE都是DESC。混合ASC和DESC将击败的可用性INDEX。(MySQL 8.0 可以解决这个问题。)
另请注意,这假设您不关心行在created_at重复时的顺序,但您确实需要一致的顺序。请注意,这uuid似乎是随机的,但仍然是一致的。话虽如此,id(有或没有 Galera)并且uuid工作得同样好。
(UUID 很烂,但这是一个不同的讨论。)
更多关于不使用OFFSET.
| 归档时间: |
|
| 查看次数: |
5594 次 |
| 最近记录: |