0

我最近想出了一个问题。我们想分批从 Oracle DB 中获取数据表,其中一个批次例如为 4-5000。我以前的“一般”解决方案是将选择包装成以下某种东西:

SELECT * FROM (
    SELECT ROWNUM AS RN, INNERSELECT.* FROM (
        select THINGS1, THINGS2 from MYTABLE)
    )
INNERSELECT WHERE ROWNUM < 4001) WHERE RN >= 3001

似乎很慢,因为当 rownum 边界很高(例如 4-500.000)时,选择将花费超过 10-20 秒。随着我增加值,时间线性增加。我当然知道为什么,所以我想找到另一种解决方案来批量获取数据,但有保证的时间框架。那么我使用了这种选择:

SELECT * FROM (
  SELECT INNERSELECT.*, ROW_NUMBER() OVER (ORDER BY INNERSELECT.ROWID) RN FROM 
    ( select THINGS1, THINGS2 from MYTABLE)
    INNERSELECT
) WHERE RN BETWEEN 3001 AND 4000;

这有点慢(获得一批测试数据需要 3-4 秒),但我可以增加批量大小而不会出现明显的性能下降,并且对于高值也是如此。当前的问题是我从数据库的多个线程中的多个表中进行选择,如果我只使用 3 个线程,性能就会下降到地狱(我们不是在谈论当前用于项目的 16 个)。JDBC 连接是池化的,性能下降在服务器端。我认为很明显 select 正在消耗 CPU 时间,所以我无能为力,但我希望大家对如何优化它有一些提示或技巧。

另一个问题是我们使用的工具不是特定于项目的,它必须尽可能通用,所以我不能使用复制表等。

感谢您提前回答

4

2 回答 2

1

假设MYTABLE有一个数字主键ID,一种策略是让 16 个线程中的每一个线程执行此查询:

SELECT THINGS1, THINGS2
FROM   MYTABLE
WHERE  MOD(ID,15) = :THREAD_NUMBER

每个线程将获得一个:THREAD_NUMBER从 0 到 15 的唯一值。这意味着,每个线程将获得(大约)1/16 的行。

于 2012-08-06T20:23:57.030 回答
0
SELECT * FROM (
  SELECT INNERSELECT.*, ROW_NUMBER() OVER (ORDER BY INNERSELECT.ROWID) RN FROM 
    ( select THINGS1, THINGS2 from MYTABLE)
    INNERSELECT
) WHERE RN BETWEEN 3001 AND 4000;

(从 MYTABLE 中选择 THINGS1、THINGS2)

这检索了多少行?如果您可以对此设置某种限制条款 - 它可以避免系统必须执行 FULL TABLE SCAN 或 INDEX SCAN。

ORDER BY INNERSELECT.ROWID

有必要发出这种类型的吗?特别是因为排序标准是系统生成的值。大型排序会对数据库产生巨大影响。

要记住的重要一点是在 Oracle 中使用 ROWNUM 提取记录 - 数据库将 ROWNUM 应用于记录作为最后一件事〜但在 ORDER BY 之前。

于 2012-08-06T20:03:16.637 回答