使用分页获取大量数据

问题描述 投票:0回答:3

举例来说,假设我有一个

Cloud
环境和一个
Client
环境,我想将大量数据从云端同步到客户端。假设我在云中有一个名为
Files
的数据库表,并且我希望客户端环境中存在完全相同的表。

现在让我们假设一些事情:

  1. 文件表很大。
  2. 文件中每一行的数据可以随时更新,并有一个
    last-update
    列。
  3. 我想获取增量并确保我在两个环境中都是相同的。

我的解决方案:

  1. 我首先进行完全同步,将所有条目返回给客户端。
  2. 我将
    LastSync
    时间保留在客户端环境中,并不断同步
    LastSync
    时间的增量。
  3. 我使用分页进行完全同步和增量同步:客户端将触发第一个请求来获取增量结果的
    Count
    ,以及每个请求的
    Page Size
    所需的许多其他请求。

例如计数:

SELECT COUNT(*) FROM files WHERE last_update > @LastSyncTime

页面抓取:

SELECT col1, col2..
FROM files 
WHERE last_update > @LastSyncTime
ORDER BY files.id
LIMIT @LIMIT 
OFFSET @OFFSET

我的问题:

例如,如果第一次提取(

Count
提取)需要一些时间(例如几分钟),并且此时更多条目已更新并添加到
last-update
提取中,该怎么办。

例如:

  • 计数获取为
    last-update 1000 seconds
    提供了 100 个条目。
  • 在获取
    Count
    时更新了 1 个条目。
  • 现在
    last-update 1000 seconds
    将给出101个条目。
  • 页面获取只会从 101 个条目中获取 100 个条目,顺序为
    id
  • 1 个条目丢失且未同步到客户端

我尝试了另外 2 个选项:

  • from-to
    last-update
    日期限制同步。
  • last-update
    而非
    id
    栏排序。

我发现这两个选项都有问题。

c# mysql pagination data-paging
3个回答
2
投票
  • 请勿使用

    OFFSET
    LIMIT
    ;它从好的到慢到更慢。 相反,请使用
    last_update
    跟踪“您离开的位置”,以便提高效率。 更多讨论

  • 由于日期时间可能重复,因此请灵活决定一次要执行的行数。

  • 持续运行此操作。 除非作为“保持活动”,否则不要使用 cron。

  • 无需初始副本;这段代码可以帮您完成。

  • 拥有

    INDEX(last_update)

  • 至关重要

这是代码:

-- Initialize.  Note: This subtract is consistent with the later compare. 
SELECT @left_off := MIN(last_update) - INTERVAL 1 DAY
    FROM tbl;

Loop:

    -- Get the ending timestamp:
    SELECT @cutoff := last_update FROM tbl
         WHERE last_update > @left_off
         ORDER BY last_update
         LIMIT 1  OFFSET 100;   -- assuming you decide to do 100 at a time
    -- if no result, sleep for a while, then restart

    -- Get all the rows through that timestamp
    -- This might be more than 100 rows
    SELECT * FROM tbl
        WHERE last_update > @left_off
          AND last_update <= @cutoff
        ORDER BY last_update
    -- and transfer them

    -- prep for next iteration
    SET @left_off := @cutoff;

Goto Loop

SELECT @cutoff
会很快——它是对索引中 100 个连续行的简短扫描。

SELECT *
完成繁重的工作,并且花费的时间与行数成正比 -
OFFSET
没有额外的开销。 读取 100 行大约需要 1 秒(假设旋转磁盘,非缓存数据)。

我不会首先获得

COUNT(*)
,而是先获得
MAX(last_update)
,因为代码的其余部分基于
last_update
。 该查询是“瞬时的”,因为它只需要探测索引的末尾。 但我声称你甚至不需要那个!

一个可能的错误:如果“源”中的行可以被删除,你如何识别这一点?


0
投票

根据数据的大小以及数据是否“公开”使用或可以在多个客户端之间使用,将数据拆分可能会有所帮助。 例如,创建每日“增量”完整数据集并缓存它们。这样,就不需要在第一次加载时一遍又一遍地查询数据库以获取每个客户端需要的数据。

  1. 尽量减少对大数据表的访问(如果数据完全没有变化,则进行异地缓存)。
  2. 卸载并缓存经常查询的常用数据。这样你就可以减少 SQL 查询的数量。
  3. last_update
    id
    上创建索引应该有助于加快从数据库实时获取增量行的速度。

可能的解决方案:

  1. 每当有新项目出现时,数据库每小时创建/每 x 次完成集。

  2. 客户端在第一次从缓存中获取时获取“每日增量/小时增量”。

  3. 客户端直接从数据库获取自上次增量“最新项目”以来的所有项目。

可能有帮助:


0
投票

您的方法涵盖了很多解决方法,您走错了路。

开始考虑数据库复制,它将抽象所有这些解决方法,并为您提供解决此类问题的工具。

一篇关于最近MySQL服务器组复制的优秀文章: https://www.digitalocean.com/community/tutorials/how-to-configure-mysql-group-replication-on-ubuntu-16-04

© www.soinside.com 2019 - 2024. All rights reserved.