处理大表 - 如何逐页选择记录?

时间:2010-12-20 01:24:59

标签: sql oracle pagination

我需要对表中的所有记录执行一个过程。该表可能非常大,所以我宁愿逐页处理记录。我需要记住已经处理过的记录,因此我的第二个SELECT结果中没有包含这些记录。

像这样:

首战,  [从MyTable中选择100条记录]

第二轮,  [从MyTable中选择另外100条记录]

依旧......

我希望你能得到这张照片。我的问题是如何编写这样的select语句?

我正在使用oracle btw,但如果我也可以运行任何其他数据库,那将会很好。 我也不想使用商店程序。

非常感谢!

2 个答案:

答案 0 :(得分:2)

你提出的将桌子分成更小块的任何解决方案最终都会花费更多的时间而不是一次性处理所有内容。除非表是分区的,否则您一次只能处理一个分区。

如果全表扫描需要1分钟,则需要10分钟才能将表分成10个部分。如果表行按您可以使用的索引列的值进行物理排序,则由于聚簇因子,这将改变一点。但它无论如何都要花费更长时间而不是一次性处理它。

这一切都取决于从表中处理一行所需的时间。您可以选择通过处理数据块来减少服务器上的负载,但从性能角度来看,您无法完成全表扫描。

答案 1 :(得分:1)

您很可能希望利用Oracle的停止密钥优化,因此当您不需要时,您最终不会得到完整的表扫描。有几种方法可以做到这一点。第一种方式是写一点时间,但让Oracle自动计算出涉及的行数:

select *
from
(
  select rownum rn, v1.*
  from (
    select *
    from table t
    where filter_columns = 'where clause'
    order by columns_to_order_by
  ) v1
  where rownum <= 200
)
where rn >= 101;

您还可以使用FIRST_ROWS提示实现相同的目的:

  select /*+ FIRST_ROWS(200) */ *
  from (
    select rownum rn, t.*
    from table t
    where filter_columns = 'where clause'
    order by columns_to_order_by
  ) v1
  where rn between 101 and 200;

我更喜欢rownum方法,因此您不必继续更改提示中的值(这需要表示结束值而不是实际返回到页面的行数是准确的)。您可以将开始和结束值设置为绑定变量,这样就可以避免硬解析。

有关详细信息,请查看this post