为什么我似乎不能强制Oracle 11g为单个SQL查询消耗更多的CPU

我有一些庞大的查询运行在巨大的桌子上。 这些查询似乎是CPU瓶颈,并运行几个小时。 据我所知,Oracle有11g的许多新function,第2版可以在内部使查询执行同步。 然而,无论我在查询中join什么样的提示,我都不能在数据库框中使用多于一个的CPU。 我有一个非常值得尊敬的有8个CPU的Solaris机器,但是每次运行这个查询时,我最终都会把一个CPU推到100%,然后在那里坐几个小时。

我试过的提示是:

SELECT /*+ PARALLEL */ ... SELECT /*+ PARALLEL(5) */ ... SELECT /*+ PARALLEL(10) */ ... 

在看盒子上的整体CPU消耗时,似乎没有任何工作。 它似乎总是挂100%的一个CPU。 不幸的是,即使解释计划似乎永远运行。 我会尝试用不同的提示获得不同的解释计划,看看是否有帮助。 有些查询可能是不可并行的,即使它们的运行时间在几小时之内? 这个查询中的主表有3.35亿行。

SQL查询文本:

http://pastie.org/8634380

系统参数:

http://pastie.org/8634383

编辑

详细解释计划 – 无并行:

http://pastebin.com/HkZgbPpf

优化器相关的系统参数:

http://pastie.org/8639841

进一步编辑:我们已经与Oracle联系了解为什么EXPLAIN PLAN需要2个多小时。 我们正在试图运行各种解释计划。

了解Oracle并行性最重要的是它很复杂。 优化并行性需要大量的Oracle知识,阅读手册,检查许多参数,testing长时间运行的查询以及大量的怀疑。

问正确的问题

平行问题真的涉及三个不同的问题:

  1. 请求了多less台并行服务器?
  2. 分配了多less台并行服务器?
  3. 有多less个并行服务器被有意义地使用?

使用最佳工具

直接去最好的工具 – 带有活动报告的SQL Monitoring。 find你的SQL_ID并生成HTML报告: select dbms_sqltune.report_sql_monitor(sql_id => 'your_sql_id', type => 'active') from dual; 。 这是知道在执行计划的每一步花了多less时间的唯一方法。 它会告诉你多less平行度被有效地使用,以及在哪里。 例如: 在这里输入图像描述

另一个好的select是type => 'text' 。 它没有太多的信息,但看起来更容易分享。

SQL监视还包括请求的DOP和分配的DOP: 在这里输入图像描述

一个100行的并行select可能会运行得很漂亮,但是由于未被caching的序列,所有事件都会一步停止。 您可以盯着解释计划,跟踪或AWR报告几个小时,而不会看到问题。 活跃的报告使缓慢的步骤几乎微不足道。 不要浪费时间猜测问题出在哪里。

但是,其他工具仍然是必需的。 使用explain plan for ...生成的explain plan for ...select * from table(dbms_xplan.display) ; 将提供一些关键信息。 特别是Notes部分可以包含很多为什么查询不要求并行性的原因。

但是为什么我得到了这个并行服务器的数量?

相关信息分散在几个不同的手册中,这些手册非常有用,但偶尔也不准确或误导。 对于并行性有很多的神话和不好的build议。 随着每个版本的发布,技术也发生了重大变化

将所有信誉良好的资源放在一起时,影响并行服务器数量的因素列表惊人地大。 下面的列表大致sorting是我认为是最重要的因素:

  1. 操作间并行性使用sorting或分组的任何查询都将分配两倍于DOP的并行服务器。 这可能是“Oracle分配尽可能多的并行服务器”这个神话的原因。
  2. 查询提示最好是一个像/*+ parallel */这样的语句级提示,或者可能是像/*+ noparallel(table1) */这样的对象级提示。 如果计划的特定步骤是以串行方式运行的,通常是因为只有部分查询的对象级提示。
  3. recursionSQL一些操作可以并行运行,但可以通过recursionSQL有效地进行序列化。 例如,一个大的插入未caching的序列。 生成parsing语句的recursionSQL也是串行的; 例如dynamic采样查询。
  4. alter session alter session [force|enable] parallel [query|dml|ddl]; 请注意,并行DML默认是禁用的。
  5. 表度
  6. 指标程度
  7. 索引更便宜并行提示仅告诉优化器考虑使用特定DOP的全表扫描。 他们并不强迫并行。 如果认为它更便宜,优化器仍然可以自由使用串行索引访问。 ( FULL提示可能有助于解决此问题。)
  8. 计划pipe理 SQL计划基线,轮廓,configuration文件,高级重写和SQL转换器都可以改变背后的并行度。 检查计划的注释部分。
  9. 版本只有企业和个人版允许并行操作。 除了包DBMS_PARALLEL_EXECUTE 。
  10. PARALLEL_ADAPTIVE_MULTI_USER
  11. PARALLEL_AUTOMATIC_TUNING
  12. PARALLEL_DEGREE_LIMIT
  13. PARALLEL_DEGREE_POLICY
  14. PARALLEL_FORCE_LOCAL
  15. PARALLEL_INSTANCE_GROUP
  16. PARALLEL_IO_CAP_ENABLED
  17. PARALLEL_MAX_SERVERS这是整个系统的上限。 这里有一个权衡。 一次运行太多的并行服务器对系统不利。 但是将查询降级为串行对于某些查询可能是灾难性的。
  18. PARALLEL_MIN_PERCENT
  19. PARALLEL_MIN_SERVERS
  20. PARALLEL_MIN_TIME_THRESHOLD
  21. PARALLEL_SERVERS_TARGET
  22. PARALLEL_THREADS_PER_CPU
  23. RAC节点的数量默认DOP的另一个乘数。
  24. CPU_COUNT如果使用默认的DOP。
  25. RECOVERY_PARALLELISM
  26. FAST_START_PARALLEL_ROLLBACK
  27. configuration文件 SESSIONS_PER_USER也限制并行服务器。
  28. 资源pipe理器
  29. 系统负载如果parallel_adaptive_multi_user为true。 当Oracle将启动节stream时可能无法猜测。
  30. PROCESSES
  31. 并行DML限制如果出现以下情况,则并行DML将不起作用:
    1. COMPATIBLE <9.2用于分区内
    2. INSERT VALUES,带有触发器的表格
    3. 复制
    4. 自我参照完整性或删除级联或延迟完整性约束
    5. 访问一个对象列
    6. 与LOB的非分区表
    7. 与LOB的分区内并行性
    8. 分布式事务
    9. 聚簇表
    10. 临时表
  32. 标量子查询不会并行运行? 这是在手册中,我希望这真实的,但我的testing表明,并行在11g工作在这里。
  33. ENQUEUE_RESOURCES 10g中的隐藏参数是否与此相关?
  34. 索引组织的表不能直接path并行插入到IOT? (这是真的吗?)
  35. 并行stream水线function要求必须使用CURSOR (?)。 去做。
  36. 函数必须是PARALLEL_ENABLE
  37. 声明的types旧版本根据分区在DML上限制并行性。 一些目前的手册仍然包括这一点,但它肯定不是真的了。
  38. 分区数量仅适用于旧版本的分区智能连接(?)
  39. 错误具体来说,我已经看到了很多与parsing错误。 Oracle将分配正确数量的并行服务器,但是不会发生任何事情,因为它们都等待cursor: pin s wait on x这样的事件cursor: pin s wait on x

此列表当然不完整,不包括12cfunction。 它不涉及操作系统和硬件问题。 而且它并不回答这个可怕的难题:“最好的并行度是多less?” (简而言之,更多的通常会更好,但是会牺牲其他stream程。)希望它至less能让您了解这些问题的难度,以及开始寻找的好地方。

因此,Oracle在这里使用了一个star_transformation,它本质上是一种组合多个位图索引的方法,以在主表上提供一组rowid。 使用rowid来访问表并不是一个非常平行的操作,全表扫描将是(或者最好是对分区子集的扫描)。

Oracle正在使用star_transformation,因为Oracle估计只有相对较less的行将匹配所有这些条件 – 听到1500万行的估计值是否正确会很有趣。 15/335大约占表行的4.4%,所以表面上使用基于索引的方法的决定是合适的,除非行最终在块之间完全随机分散,并且访问30%的块。

无论如何,我有一种感觉,如果甲骨文将select一个star_transformation然后平行的提示变得无关紧要。

star_transformation的替代方法是在大表上使用全表扫描,所以我认为首先要提示全表扫描并行性。 你也可以发出一个alter session命令来临时禁用星形转换,但是暗示的重要部分是在进入并行之前确切地说明你想要的访问方式。

进一步注意:顺便说一下,您在计划中看到的临时表是由于星形转换 – 当维度表首先被扫描以查找适用的行时,Oracle不再需要在返回期间再次find有用的子集通过将它们存储在临时表中来实现查询的阶段。 你可以禁用这个行为,但是这可能在这里很好。

另一个注意:再看看解释计划 – 那些00:27:44,00:27:45等时间是累积的。 它们包括例如00:27:43的表访问索引行号/ B28 / EUDIQSBV。 如果考虑到这一点,你会发现散列连接每个都需要几秒钟,性能猪群是3小时左右的HASH GROUP BY。 根据估计,它使用了4GB的临时空间。 这可能是一个严重的漏洞 – 使用V $ SQL_WORKAREA来监视执行的次数,看它有多less次传递,但只要有存储带宽,PQ就是一个答案。

PARALLEL操作可以在某些特定情况下带来价值,如果您只是将PARALLEL提示放入查询中,这并不意味着Oracle将并行任何特定的东西。 请看下面的例子:

 SQL> select * from t 2 where id = 14 3 / Execution plan ---------------------------------------------------------- Plan hash value: 1859958591 -------------------------------------------------------------------------------- ---------------------------- | Id | Operation | Name | Rows | Byt es | Cost (%CPU)| Time | -------------------------------------------------------------------------------- ---------------------------- | 0 | SELECT STATEMENT | | 5210 | 21 67K| 478 (1)| 00:00:06 | | 1 | TABLE ACCESS BY INDEX ROWID| T | 5210 | 21 67K| 478 (1)| 00:00:06 | |* 2 | INDEX RANGE SCAN | T_FK_I | 5210 | | 20 (0)| 00:00:01 | -------------------------------------------------------------------------------- ---------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("ID"=14) Statistics ---------------------------------------------------------- 17 recursive calls 0 db block gets 10607 consistent gets 0 physical reads 0 redo size 3734464 bytes sent via SQL*Net to client 994894 bytes received via SQL*Net from client 7256 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 5295 rows processed SQL> select /*+ parallel(4) */ * from t 2 where id = 14 3 / Execution plan ---------------------------------------------------------- Plan hash value: 1859958591 -------------------------------------------------------------------------------- ---------------------------- | Id | Operation | Name | Rows | Byt es | Cost (%CPU)| Time | -------------------------------------------------------------------------------- ---------------------------- | 0 | SELECT STATEMENT | | 5210 | 21 67K| 478 (1)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| T | 5210 | 21 67K| 478 (1)| 00:00:01 | |* 2 | INDEX RANGE SCAN | T_FK_I | 5210 | | 20 (0)| 00:00:01 | -------------------------------------------------------------------------------- ---------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("ID"=14) Note ----- - Degree of Parallelism is 1 because of hint Statistics ---------------------------------------------------------- 17 recursive calls 0 db block gets 10607 consistent gets 0 physical reads 0 redo size 3734464 bytes sent via SQL*Net to client 994894 bytes received via SQL*Net from client 7256 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 5295 rows processed SQL> select /*+ full(t) */ * from t 2 where id = 14 3 / Execution plan ---------------------------------------------------------- Plan hash value: 565085413 -------------------------------------------------------------------------------- --------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| T ime | -------------------------------------------------------------------------------- --------- | 0 | SELECT STATEMENT | | 5210 | 2167K| 3858 (1)| 0 0:00:47 | |* 1 | TABLE ACCESS FULL| T | 5210 | 2167K| 3858 (1)| 0 0:00:47 | -------------------------------------------------------------------------------- --------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("ID"=14) Statistics ---------------------------------------------------------- 17 recursive calls 1 db block gets 19468 consistent gets 507 physical reads 0 redo size 3734334 bytes sent via SQL*Net to client 994894 bytes received via SQL*Net from client 7256 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 5295 rows processed SQL> select /*+ parallel(4) full(t) */ * from t 2 where id = 14 3 / Execution plan ---------------------------------------------------------- Plan hash value: 298470658 -------------------------------------------------------------------------------- ----------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time | TQ |IN-OUT| PQ Distrib | -------------------------------------------------------------------------------- ----------------------------------------- | 0 | SELECT STATEMENT | | 5210 | 2167K| 1070 (1) | 00:00:03 | | | | | 1 | PX COORDINATOR | | | | | | | | | | 2 | PX SEND QC (RANDOM)| :TQ10000 | 5210 | 2167K| 1070 (1) | 00:00:03 | Q1,00 | P->S | QC (RAND) | | 3 | PX BLOCK ITERATOR | | 5210 | 2167K| 1070 (1) | 00:00:03 | Q1,00 | PCWC | | |* 4 | TABLE ACCESS FULL| T | 5210 | 2167K| 1070 (1) | 00:00:03 | Q1,00 | PCWP | | -------------------------------------------------------------------------------- ----------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - filter("ID"=14) Note ----- - Degree of Parallelism is 4 because of hint Statistics ---------------------------------------------------------- 12 recursive calls 65 db block gets 17262 consistent gets 14401 physical reads 0 redo size 3736075 bytes sent via SQL*Net to client 994894 bytes received via SQL*Net from client 7256 SQL*Net roundtrips to/from client 0 sorts (memory) 0 sorts (disk) 5295 rows processed 

正如你可以看到当我刚刚添加PARALLEL提示的查询我仍然有索引访问。 你应该首先分析你的执行计划和统计数据,得到的答案是你现在的计划如此糟糕,你相信吗? 可能是最好的。 正如你也可以看到并行全扫描显着更多的逻辑读取(包括磁盘读取),所以如果并行度是不相关的,你可以得到性能下降,而不是任何胜利。 最后但并非最不重要的一点 – 你是否认为这种看法是划分的? 如果您需要按照稳定和可预测的标准获取一小部分数据,这可能会非常有帮助。