【问题标题】:oracle improve query performanceoracle提高查询性能
【发布时间】:2013-01-16 23:30:41
【问题描述】:

我是 Oracle 新手,我必须解决这个问题。

我有一张表,里面有大约 5.2 亿行。我必须获取所有行并将它们导入(非规范化)到 NoSQL 数据库中。

该表有两个整数字段 C_ID 和 A_ID 以及 3 个索引,一个在 C_ID 上,一个在 A_ID 上,一个在两个字段上。

我一开始就尝试过这种方式:

SELECT C_ID, A_ID FROM M_TABLE;

这从来没有在合理的时间内给我任何结果(我无法测量时间,因为它似乎永远不会完成)。

我以这种方式更改了查询:

SELECT /*+ ALL_ROWS */ C_ID, A_ID FROM (SELECT
    rownum rn, C_ID, A_ID
FROM
    M_TABLE WHERE rownum < ((:1 * :2 ) +1 )) WHERE rn >= (((:1 -1) * :2 ) +1 );

我使用 3 个线程并行运行此查询,并使用大小为 1000 的页面进行分页。

我尝试引入三个优化:

1) 我在表格上创建了​​统计信息:

ANALYZE TABLE TABLE_M ESTIMATE STATISTICS SAMPLE 5 PERCENT;

2) 我将表划分为 8 个分区。

3) 我使用并行选项创建了表。

现在我能够每秒获取 10000 行,因此整个过程大约需要 15 个小时才能完成(数据库在 4 核、8 GB 机器上运行)。

问题是我需要在最多 5 小时内完成所有工作。

我没有想法,所以在我要求新机器之前,您知道在这种情况下提高性能的任何方法。

【问题讨论】:

  • 索引在这里没有帮助。您正在全面扫描表格。而且我不明白该分页如何帮助您。它不会工作。
  • 我认为我所做的真正优化在于查询更改。
  • 抱歉,我撤回了关于分页查询的断言,它可能会起作用,但是当然你做的工作比需要的多,每次都读取第一个块。开始时你会很快,但结束时会很慢。
  • 是的,我注意到了这一点;这个过程在第一页非常快,并且变得越来越慢。您有什么避免这种情况的建议吗?
  • 从关系数据库获取数据花费了多少时间,插入 NoSQL 数据库花费了多少时间?您是否已对您的应用进行了概要分析?

标签: sql performance oracle select


【解决方案1】:

你如何处理你的结果?它是使用 PL/SQL 直接获取到文件还是使用另一个应用程序来处理数据?是通过网络发送的吗? (这可能是唾手可得的果实)。

我问的原因是FULL SCAN(没有 ORDER BY)通常会立即返回第一行。如果您将结果输出到文件,您应该会看到它立即开始填满。如果不这样做,这意味着段的开头有很多空白空间,这可以解释为什么查询永远不会返回(至少在合理的时间内)。

所以当你说你的查询没有返回时,我有点担心,你怎么知道?以下块是否返回?

DECLARE
  l NUMBER := 0;
BEGIN
  FOR cc IN (SELECT C_ID, A_ID FROM M_TABLE) LOOP
    l := l + 1;
    EXIT WHEN l >= 100000;
  END LOOP;
END;

如果是,则表示您的 FULL SCAN 正在处理中。通过对上述查询进行计时,您应该能够计算出完整的单个 SCAN 需要多少时间,假设该段是均匀密集的。

读取 500M 行的工作量很大,但是这些行很小,所以如果表段被很好地压缩,Oracle 应该在合理的时间内返回所有行。例如,如果重复删除然后加载INSERT /*+APPEND*/,则表段的空间配置可能会效率低下。重建表 (ALTER TABLE MOVE) 将删除段中所有空的无用空间。顺便说一下,当您对表进行分区时,您确实重建了它,所以这可能是您的查询现在返回的原因!

在任何情况下,我都建议您重试 FULL TABLE SCAN,可能在重建表以重置任何空白空间和高水位标记之后。迄今为止,单次全表扫描是访问大量数据的最可靠方法(也是最有效的方法之一)。

如果你需要进一步提高性能,我建议你看看ROWID分区(DIY parallel processing方案)或者内置包DBMS_PARALLEL_EXECUTE。

【讨论】:

  • 除此之外,您还可以在运行完整扫描时查看 V$SESSION_LONGOPS 以了解扫描的距离以及预计需要多长时间。
  • 我正在使用“libocci”库从远程机器(在同一子网中)获取数据
  • 您是否看到通过 FULL SCAN 获取的行?
  • 我再次转到此查询:SELECT /*+ ALL_ROWS PARALLEL*/ channel_id, account_id FROM M_TABLE; 它似乎工作得更快(也因为我在SPFILE 范围内启用了PARALLEL_AUTOMATIC_TUNING)。现在,观察计划,我在桌子上只看到“INDEX FULL SCAN”和“INDEX FAST FULL SCAN”。我按照建议使用 V$SESSION_LONGOPS 来观察查询的运行情况,我注意到这个过程非常快,直到工作达到“排序输出”步骤;这似乎是这个过程的瓶颈。
  • 我觉得我看错了;你可以在这里找到计划:http://pastebin.com/tJY4N2GT。无论如何,我再次更改了我的查询,现在它似乎在大约 5 小时 20 分钟内给了我结果;这是新版本:SELECT /*+ ALL_ROWS PARALLEL*/ channel_id, account_id FROM (SELECT channel_id, account_id, rownum AS rn FROM M_TABLE) WHERE rn &gt;= (((:1 -1)* :2) + 1) AND rownum &lt;= :2我现在正在使用大小为 1000000 的页面。我认为 ROWID 分区和使用您发布的架构增强的并行处理是我收到的主要帮助。
【解决方案2】:

Oracle 非常聪明地告诉我们它把时间花在了哪里。您可以通过使用 Oracle 的扩展 SQL 跟踪(即 10046 跟踪)跟踪会话来做到这一点。您的查询正在从一个包含大量数据的表中提取数据。检查您的 IO 速率 (db_file_scattered_read),这可能是您查询的最重要的等待事件之一。

希望对你有帮助。

【讨论】:

    【解决方案3】:

    尝试这可能是一个激进的解决方案,但您可以查看表压缩。在 Oracle 10g 中,这仅对只读表真正有用,因为在完成写操作时块是未压缩的。我发现压缩对于数据仓库环境中的大型表很有用。

    也可以只压缩某些分区,以便将数据添加到按日期分区的表的末尾,您可以压缩历史分区,同时不压缩最近的分区。

    表压缩的优势在于它减少了所需的 I/O 数量,这有助于 I/O 受限的系统。尽管这取决于表中存储的内容以及插入数据时使用的排序方式,但我经常对表进行 10:1 压缩。

    对于现有的表,我认为您可以使用以下命令:

    ALTER TABLE M_TABLE COMPRESS MOVE;
    

    请注意,这可能有助于解决您的问题,但更改表的底层结构可能有点过激。此外,将表重建为压缩表可能会使某些索引无效。

    在 Oracle 11g 下,您还可以使用高级压缩来更新数据,但这会涉及昂贵的许可成本。

    here 中有一些文档,this PDF document 中有更多信息

    【讨论】:

    • 好主意!压缩功能是否适用于所有 DB 版本?
    • @VincentMalgrat 不确定。认为它在所有版本中都可用,但并不完全确定。 Oracle 11g 高级压缩需要额外付费,但我认为所有版本都有标准压缩。
    【解决方案4】:

    是的,正如 user2033072 所说,您应该使用 SQL Trace 和 TkProf 来了解有关查询的更多信息。你可以看到official documentation。

    此外,您可以更简单地使用explain plan,这样甲骨文就会显示它的计划。

    【讨论】:

    • 我从未见过列或列顺序会影响索引的使用。您是否有任何有关此行为的文档参考?他选择了表中超过 12% 的行(在这种情况下所有行都没有谓词),因此优化器不会使用索引。
    • @Wolf 嗨,你可以在这里看到:docs.oracle.com/cd/B19306_01/server.102/b14211/optimops.htm 在 13.5.3.6 完整扫描和 13.5.3.7 快速完整索引扫描部分中,如果优化器不考虑它,也会有提示.它仅适用于包含查询中所需的所有数据的索引(如本例所示)。
    • 我以前读过,如果索引中的所有数据都可用,优化器可能会决定不命中表。我阅读了提供的注释,然后尝试创建一个大表和索引并运行几个测试。我能够让优化器使用带有 INDEX_FFS 提示的快速全扫描,并且如果一列不为空(如文档所述),则没有谓词,尽管成本上升(这可能无关紧要,并且不确定执行时间)。但是,文档和我的测试显示列顺序没有区别。很有趣。
    • 我认为您对订单的看法是正确的。我犯了一个错误。仅在位置或订购时才重要...我将其从答案中删除。
    猜你喜欢
    • 2018-11-27
    • 1970-01-01
    • 1970-01-01
    • 2013-08-03
    • 2021-12-27
    • 2019-05-23
    • 2021-08-03
    • 2013-02-17
    相关资源
    最近更新 更多