0

我有一个程序需要对许多非常大的 Oracle 表(最大的有数千万行)运行查询。这些查询的输出被馈送到另一个进程(作为副作用)可以记录查询的进度(即,最后一行获取)。

如果任务由于某种原因中途停止,它可以重新启动,那将是很好的。为此,查询必须以一致的顺序返回行,因此必须对其进行排序。显而易见的事情是对主键进行排序;但是,与未排序的解决方案相比,这可能会在性能(索引访问)方面受到惩罚。鉴于重启可能永远不会发生,这是不可取的。

是否有一些技巧可以确保以另一种方式进行一致的排序?在这种情况下保持性能的任何其他建议?

编辑:我一直在环顾四周,看到提到“按 rowid 排序”。这有用甚至可能吗?

EDIT2:我添加了一些基准:

  • 无订单:17 秒。
  • 通过 PK 订购:46 秒。
  • 按 rowid 排序:43 秒。

因此,任何 order by 都会对性能产生严重影响,而使用 rowid 几乎没有什么区别。公认的答案是 - 没有简单的方法可以做到这一点。

4

3 回答 3

3

我能想到的最好的建议是减少发生可能停止进程的问题的机会,这意味着保持代码简单。没有游标,没有提交,没有试图移动部分数据,只是直接的 SQL 语句。

除非完全重启将是一场完全不可接受的灾难,否则我会为了简单起见而根本没有任何中途重启代码。

于 2015-04-09T16:37:18.487 回答
1

如果您想要一些订单并且查询的数据未排序,那么您无论如何都需要对其进行排序,并花费一些资源进行排序。
因此,至少有两种优化变体:

  1. 尽量减少用于分类的资源;
  2. 查询已排序的数据。

对于第一个变体,Oracle 自己计算一个最佳变体,以最大限度地减少数据访问和总体查询时间。可以选择优化器已经使用的唯一索引中涉及的排序顺序,但这是一个非常值得怀疑的策略。

第二个变体是关于索引组织表和关于强制 Oracle 使用某些特定索引的提示。如果您需要处理某个特定表中的几乎所有记录,这似乎没问题,但是如果查询的选择性很高,那么即使在单个表上,它也会显着减慢进程。

考虑一个具有代理主键的表,其中包含具有 10 年交易历史的数据。如果您只需要前一年的数据并且您强制按主键排序,那么 Oracle 需要一个一个地处理所有 10 年的记录,以查找属于单个年份的所有记录。
但是如果你需要这张表 9 年的数据,那么全表扫描可能比基于索引的选择更快。
因此,查询的选择性是在全表扫描和结果排序之间进行选择的关键。

对于存储结果和重新启动查询,一个好的解决方案是使用 Oracle Streams Advanced Queuing来提供另一个进程。
队列中所有未处理的消息都重定向到异常队列,在那里可以单独处理。
因为您没有为选定的消息指定确切的顺序,所以我想您只需要排序来维护记录的未处理部分。如果这是真的,那么使用 AQ,您根本不需要订购,甚至可以并行处理记录。

所以,最后,从我的角度来看,缓冲队列是你真正需要的。

于 2015-04-09T17:15:55.837 回答
0

SET is_processed = 'Y'您可以跳过排序,只需使用类似或更新您处理的记录SET date_processed = sysdate。完全可重新启动,无需排序。

为了提高性能,您可以按 is_processed 进行分区。是的,分区键更改可能会很慢,但这完全取决于权衡。

于 2015-04-10T08:03:23.897 回答