【问题标题】:Fetch rows in batches from a table/tables in guaranteed order in SQL Server 2016在 SQL Server 2016 中以保证顺序从表中批量获取行
【发布时间】:2018-10-17 20:01:11
【问题描述】:

我正在 java 中创建一个批量加载实用程序,它将从源数据库的表中读取行并在目标数据库为空时填充目标数据库中的数据。

我从下面的 select 语句开始:这将返回批次,因为 order by 子句保证了订单。假设在此批量实用程序处理过程中没有插入具有过去日期 (created_date) 的记录,则一切正常。

SELECT * FROM dbo.${batch.name}
        ORDER BY created_date
        OFFSET ${batch.offset} ROWS
        FETCH NEXT ${batch.batchSize} ROWS ONLY;

但后来我意识到有些表没有 created_date 列。

如果您不指定明确的 order by 子句,则无法保证 SQL-Server 的顺序。所以我不能删除 order by,但是由于 created_date 不在所有表中,所以这个查询会失败。

考虑到所有表都没有用于 order by 子句的公共列或任何可以按插入顺序返回行的查询,是否有通用选择查询可以按顺序返回行?

以下查询是否有效?如果在此批处理实用程序使用以下查询进行时插入了更多行怎么办?

SELECT * FROM dbo.${batch.name}
            ORDER BY (SELECT 1)
            OFFSET ${batch.offset} ROWS
            FETCH NEXT ${batch.batchSize} ROWS ONLY;

谢谢。

【问题讨论】:

  • 简短回答...不...也就是说,所有表都应该有一个主键。为什么不简单地使用它?
  • 我无法在 where 子句中指定主键来选择行,因为应用程序没有主键。我只想通过批量选择行来将整个表复制到另一个数据库。
  • 为什么要使用批处理?为什么不只使用单个查询打开一个 ResultSet 并遍历行呢? docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html
  • 在这种情况下,使用 ResultSet/Cursor 逐行处理不是一个有效的解决方案,因为数据量很大。还要考虑是否有几行无法插入我不想重新开始的目标数据中心。主要是因为游标的性能问题,而不是使用基于 ResultSet/Cursor 的方法的多线程,我想到了批处理。使用批处理我可以使用多个线程一次读取/写入多行并独立处理。如果任何批次失败,我不需要重新开始,只需要处理该批次。

标签: sql sql-server database select jdbc


【解决方案1】:

没有插入顺序之类的东西。根据定义,表是无序集。仅在您订购结果集时才会发生订购。所以不,你想要的是不可能的。更糟糕的是,您可能认为它确实如此,因为它通常会按聚集索引的顺序返回它们......直到突然它没有。

https://blogs.msdn.microsoft.com/conor_cunningham_msft/2008/08/27/no-seatbelt-expecting-order-without-order-by/

【讨论】:

【解决方案2】:

因为我们无法按插入顺序获取行,所以我将查询更改为按列对要批量加载的每个表进行排序。它有一个缺点,当批量加载过程正在进行时,我们无法插入这些表。所以需要在批量加载过程运行时拍摄源数据库的快照。

SELECT * FROM dbo.${batch.name}
        ORDER BY ${batch.orderByColumn}
        OFFSET ${batch.offset} ROWS
        FETCH NEXT ${batch.batchSize} ROWS ONLY;

感谢@Sean Lange@Jason A. Long 的回复。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-20
    • 1970-01-01
    • 2017-12-11
    • 1970-01-01
    • 2019-02-04
    • 1970-01-01
    • 2021-06-09
    • 1970-01-01
    相关资源
    最近更新 更多