使用分页

时间:2018-06-18 07:19:08

标签: c# mysql paging data-paging

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

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

  1. 文件表非常大。
  2. 文件中每行的数据可以随时更新,并且有last-update列。
  3. 我想获取delta并确保在两种环境中都相同。
  4. 我的解决方案:

    1. 我首先进行完全同步,将所有条目返回给客户端。
    2. 我将LastSync时间保留在客户端环境中并继续从LastSync时间开始同步delta。
    3. 我使用分页执行完全同步和增量同步:客户端将触发第一个请求,以获取增量的Count结果以及每个Page Size所需的其他请求请求。
    4. 例如,计数:

      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提取。< / p>

      例如:

      • Count fetch为last-update 1000 seconds提供了100个条目。
      • 在获取Count时更新了1个条目。
      • 现在last-update 1000 seconds将提供101个条目。
      • 页面提取只能通过id
      • 从101获得100个条目
      • 错过了1个条目且未同步到客户端

      我尝试过其他2个选项:

      • from-to的{​​{1}}日期限制同步。
      • last-update排序,而不是last-update列。

      我在两个选项中都看到了问题。

3 个答案:

答案 0 :(得分:1)

  • 请勿使用OFFSETLIMIT;它从确定变慢到变慢。而是使用last_update跟踪“您离开的地方”,以便提高效率。 More Discussion

  • 由于日期时间可能会有重复,因此请灵活设置一次可以执行的行数。

  • 连续运行此命令。不要将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。该查询是“即时”的,因为它只需要探测索引的末尾。但我声称您甚至不需要它!

可能的错误:如果可以删除“源”中的行,您如何识别呢?

答案 1 :(得分:0)

取决于数据的大小以及是否使用&#39; public&#39;或者可以在多个客户端之间使用它可能有助于拆分。 例如,创建每日“delta”&#39; s&#39;完成数据集并缓存它们。这样就不需要在第一次加载时反复查询每个客户端需要的数据。

  1. 尝试尽可能减少对大数据表的访问(如果数据根本不发生变化,则异地缓存)。
  2. 卸载并缓存经常使用的数据,这些数据经常被查询。所以你减少了SQL查询的数量。
  3. last_updateid上创建索引应该有助于加快速度,以便从数据库中获取实时增量线。
  4. 可能的解决方案:

    1. 每当有一些新项目出现时,每x次创建的数据库每x次设置一次。

    2. 客户获得&#34;每日三角洲/每小时三角洲&#34;在第一次从缓存中获取。

    3. 客户端提取自上次delta&#34;最新项目&#34;以来的所有项目直接来自数据库。

    4. 可能会有所帮助:

答案 2 :(得分:0)

您的方法涵盖了许多变通办法,您所采用的方法是错误的。

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

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