【发布时间】:2015-04-09 15:48:58
【问题描述】:
我有一个程序需要对许多非常大的 Oracle 表(最大的有数千万行)运行查询。这些查询的输出被馈送到另一个进程(作为副作用)可以记录查询的进度(即,最后一行获取)。
如果任务由于某种原因中途停止,可以重新启动它会很好。为此,查询必须以一致的顺序返回行,因此必须对其进行排序。显而易见的事情是对主键进行排序;但是,与未排序的解决方案相比,这可能会在性能(索引访问)方面受到惩罚。鉴于重启可能永远不会发生,这是不可取的。
是否有一些技巧可以以另一种方式确保一致的排序?在这种情况下保持性能的任何其他建议?
编辑:我一直在环顾四周,看到提到“按 rowid 排序”。这有用甚至可能吗?
EDIT2:我正在添加一些基准:
- 没有订单:17 秒。
- 按 PK 排序:46 秒。
- 按 rowid 排序:43 秒。
因此,任何 order by 都会对性能产生严重影响,使用 rowid 几乎没有什么区别。公认的答案是 - 没有简单的方法。
【问题讨论】:
-
您认为为什么会使用索引访问?如果要检索大部分数据,则索引将毫无意义。行以一致的顺序出现(例如主键升序)的唯一保证是使用
ORDER BY子句。但是,您还必须考虑诸如如果有人在查询开始和重新启动之间插入出现在有序结果集中中途的新数据怎么办?那可能会把事情搞砸。不过,对结果集进行排序很可能会对性能产生影响。 -
对于这种情况,您可以假设基础表不会被修改。如果使用 order by,我假设需要索引访问才能按顺序检索行。
-
索引不一定用于进行排序。我说的不是基础表的变化,而是说你有一个 pk id 为 1、3、5 和 7 的行,所以你在 id 列上对结果进行排序。假设您在第 3 行之后停止,然后有人插入了 id = 4 的行。当您重新启动查询时,id = 5 的行不再是结果集中的第 3 行,而是第 4 行,因此您的结果不是在两次运行中保持一致。
-
@Boneist,您如何解释“基础表正在更改”,使其不包括“有人插入一行”?
-
分区是一种选择吗?如果表是散列分区的,您可以一次处理一个分区(检索特定分区不会产生任何成本),然后从最新的分区重新启动。您实际上不需要对数据进行排序,只需将它们放入(确定性)哈希桶中就足够了。
标签: sql oracle sorting sql-order-by data-consistency