作为 SQL 开发人员或 Toad 使用 IDE 工具的 Oracle 并行查询行为

Oracle Parallel Query behaviour with IDE tools as SQL Developer or Toad

一段时间以来,我一直在努力抽出时间来写这个问题,并尽我所能解释这个问题,所以请提前原谅我的长文。

我的环境:

我们有一个非常大的数据库,其中包含许多服务于多个应用程序的模式。大多数应用程序实际上是 PL/SQL 中处理数亿条记录的批处理引擎,因此出于性能原因,大多数大型 tables 都配置了 PARALLEL DEGREE DEFAULT。表已分区并具有高级压缩功能。

除了一些用于开发目的的报告 BI 工具外,许多最终用户还可以通过 SQL 开发人员访问系统(仅在读取模式下)以进行 QA 检查。我从来不喜欢,但有时候你不得不接受事情的本来面目。

为了控制一些事情,我设计了一个特定的登录触发器,它不仅包括审计功能,还包括传入会话的某些方面:

登录触发器允许或不允许基于一组附加规则的访问,但对于问题的目的,它们并不重要。

让我们看看 运行ning 在 SQL 上的查询如何针对启用 PARALLEL 的 tables:

场景

我有一个 table 包含由不同分区拆分的 80 亿条记录。用户使用 sql 开发人员登录并 运行 执行此查询

SELECT COUNT(*) FROM MY_SCHEMA.MY_TABLE PARTITION ( MY_PARTITION ) ;

183.940.801 rows 

由于 table 没有索引,CBO 运行 会使用它认为的尽可能多的奴隶进行并行的 TABLE 全面扫描。完成需要 6 秒。到目前为止,没有任何问题。

与此同时,我正在监视会话(当查询 运行ning 时,您可以看到所有会话都处于活动状态)

  INSTANCE     SID USERNAME             PROGRAM                                            SQL_ID               STATUS
---------- ------- -------------------- -------------------------------------------------- -------------------- --------
         2       6 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00N)       dtf8d89xg7muq        ACTIVE
         2     128 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P004)       dtf8d89xg7muq        ACTIVE
         2     140 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P007)       dtf8d89xg7muq        ACTIVE
         2     256 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00O)       dtf8d89xg7muq        ACTIVE
         2     284 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00D)       dtf8d89xg7muq        ACTIVE
         2     388 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00C)       dtf8d89xg7muq        ACTIVE
         2     400 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00P)       dtf8d89xg7muq        ACTIVE
         2     510 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00E)       dtf8d89xg7muq        ACTIVE
         2     621 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00F)       dtf8d89xg7muq        ACTIVE
         2     641 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00Q)       dtf8d89xg7muq        ACTIVE
         2     739 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P008)       dtf8d89xg7muq        ACTIVE
         2     771 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P005)       dtf8d89xg7muq        ACTIVE
         2     888 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00R)       dtf8d89xg7muq        ACTIVE
         2     893 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00G)       dtf8d89xg7muq        ACTIVE
         2     996 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00H)       dtf8d89xg7muq        ACTIVE
         2    1010 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00S)       dtf8d89xg7muq        ACTIVE
         2    1015 FDM_ADM_GRID         SQL Developer                                      dtf8d89xg7muq        ACTIVE
         2    1109 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00T)       dtf8d89xg7muq        ACTIVE
         2    1116 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00I)       dtf8d89xg7muq        ACTIVE
         2    1230 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00J)       dtf8d89xg7muq        ACTIVE
         2    1254 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00U)       dtf8d89xg7muq        ACTIVE
         2    1352 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P009)       dtf8d89xg7muq        ACTIVE
         2    1376 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P001)       dtf8d89xg7muq        ACTIVE
         2    1383 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P006)       dtf8d89xg7muq        ACTIVE
         2    1477 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00V)       dtf8d89xg7muq        ACTIVE
         2    1488 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P000)       dtf8d89xg7muq        ACTIVE
         2    1506 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00K)       dtf8d89xg7muq        ACTIVE
         2    1604 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P002)       dtf8d89xg7muq        ACTIVE
         2    1617 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00L)       dtf8d89xg7muq        ACTIVE
         2    1620 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00A)       dtf8d89xg7muq        ACTIVE
         2    1740 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P003)       dtf8d89xg7muq        ACTIVE
         2    1743 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00M)       dtf8d89xg7muq        ACTIVE
         2    1851 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00B)       dtf8d89xg7muq        ACTIVE
        

查询完成后

SQL> r
  1* select inst_id as instance , sid, username, program, sql_id, status from gv$session where username = 'FDM_ADM_GRID'

  INSTANCE     SID USERNAME             PROGRAM                                            SQL_ID               STATUS
---------- ------- -------------------- -------------------------------------------------- -------------------- --------
         2    1015 FDM_ADM_GRID         SQL Developer                                                           INACTIVE
        

到目前为止一切顺利。现在让我们 运行 SQL Developer

中的另一个查询
SELECT * FROM MY_SCHEMA.MY_TABLE partition ( MY_PARTITION ) fetch first 1000 rows only;

查询几乎立即检索前 1000 行。但是让我们看看数据库的区别

运行宁

的时候
SQL> r
  1* select inst_id as instance , sid, username, program, sql_id, status from gv$session where username = 'FDM_ADM_GRID'

  INSTANCE     SID USERNAME             PROGRAM                                            SQL_ID               STATUS
---------- ------- -------------------- -------------------------------------------------- -------------------- --------
         2       6 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00N)       9jyvj64ag15mv        ACTIVE
         2     128 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P007)       9jyvj64ag15mv        ACTIVE
         2     140 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P004)       9jyvj64ag15mv        ACTIVE
         2     256 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00D)       9jyvj64ag15mv        ACTIVE
         2     284 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00O)       9jyvj64ag15mv        ACTIVE
         2     388 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00P)       9jyvj64ag15mv        ACTIVE
         2     400 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00C)       9jyvj64ag15mv        ACTIVE
         2     510 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00E)       9jyvj64ag15mv        ACTIVE
         2     621 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00F)       9jyvj64ag15mv        ACTIVE
         2     641 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00Q)       9jyvj64ag15mv        ACTIVE
         2     739 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P008)       9jyvj64ag15mv        ACTIVE
         2     771 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P005)       9jyvj64ag15mv        ACTIVE
         2     888 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00G)       9jyvj64ag15mv        ACTIVE
         2     893 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00R)       9jyvj64ag15mv        ACTIVE
         2     996 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00H)       9jyvj64ag15mv        ACTIVE
         2    1010 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00S)       9jyvj64ag15mv        ACTIVE
         2    1015 FDM_ADM_GRID         SQL Developer                                                           ACTIVE
         2    1109 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00I)       9jyvj64ag15mv        ACTIVE
         2    1116 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00T)       9jyvj64ag15mv        ACTIVE
         2    1230 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00J)       9jyvj64ag15mv        ACTIVE
         2    1254 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00U)       9jyvj64ag15mv        ACTIVE
         2    1352 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P006)       9jyvj64ag15mv        ACTIVE
         2    1376 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P009)       9jyvj64ag15mv        ACTIVE
         2    1383 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P001)       9jyvj64ag15mv        ACTIVE
         2    1477 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P000)       9jyvj64ag15mv        ACTIVE
         2    1488 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00V)       9jyvj64ag15mv        ACTIVE
         2    1506 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00K)       9jyvj64ag15mv        ACTIVE
         2    1604 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P002)       9jyvj64ag15mv        ACTIVE
         2    1617 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00A)       9jyvj64ag15mv        ACTIVE
         2    1620 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00L)       9jyvj64ag15mv        ACTIVE
         2    1740 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P003)       9jyvj64ag15mv        ACTIVE
         2    1743 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00M)       9jyvj64ag15mv        ACTIVE
         2    1851 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00B)       9jyvj64ag15mv        ACTIVE

查询完成后,我再次检查,但是现在所有的奴隶都还在那里,并且处于活动状态。我本以为一旦 QC 完成并标记为非活动状态,Oracle 就会关闭所有从属进程。但它没有

  `INSTANCE     SID USERNAME             PROGRAM`                                            SQL_ID               STATUS
---------- ------- -------------------- -------------------------------------------------- -------------------- --------
     2       6 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00N)       9jyvj64ag15mv        ACTIVE
     2     128 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P007)       9jyvj64ag15mv        ACTIVE
     2     140 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P004)       9jyvj64ag15mv        ACTIVE
     2     256 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00D)       9jyvj64ag15mv        ACTIVE
     2     284 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00O)       9jyvj64ag15mv        ACTIVE
     2     388 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00P)       9jyvj64ag15mv        ACTIVE
     2     400 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00C)       9jyvj64ag15mv        ACTIVE
     2     510 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00E)       9jyvj64ag15mv        ACTIVE
     2     621 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00F)       9jyvj64ag15mv        ACTIVE
     2     641 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00Q)       9jyvj64ag15mv        ACTIVE
     2     739 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P008)       9jyvj64ag15mv        ACTIVE
     2     771 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P005)       9jyvj64ag15mv        ACTIVE
     2     888 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00G)       9jyvj64ag15mv        ACTIVE
     2     893 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00R)       9jyvj64ag15mv        ACTIVE
     2     996 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00H)       9jyvj64ag15mv        ACTIVE
     2    1010 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00S)       9jyvj64ag15mv        ACTIVE
     2    1015 FDM_ADM_GRID         SQL Developer                                                           INACTIVE
     2    1109 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00I)       9jyvj64ag15mv        ACTIVE
     2    1116 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00T)       9jyvj64ag15mv        ACTIVE
     2    1230 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00J)       9jyvj64ag15mv        ACTIVE
     2    1254 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00U)       9jyvj64ag15mv        ACTIVE
     2    1352 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P006)       9jyvj64ag15mv        ACTIVE
     2    1376 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P009)       9jyvj64ag15mv        ACTIVE
     2    1383 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P001)       9jyvj64ag15mv        ACTIVE
     2    1477 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P000)       9jyvj64ag15mv        ACTIVE
     2    1488 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00V)       9jyvj64ag15mv        ACTIVE
     2    1506 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00K)       9jyvj64ag15mv        ACTIVE
     2    1604 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P002)       9jyvj64ag15mv        ACTIVE
     2    1617 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00A)       9jyvj64ag15mv        ACTIVE
     2    1620 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00L)       9jyvj64ag15mv        ACTIVE
     2    1740 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P003)       9jyvj64ag15mv        ACTIVE
     2    1743 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00M)       9jyvj64ag15mv        ACTIVE
     2    1851 FDM_ADM_GRID         oracle@scglvdoraci0010.scger.pre.corp (P00B)       9jyvj64ag15mv        ACTIVE
     

只要会话保持打开状态,QC 将保持非活动状态,而从属设备将保持活动状态,因此尽管它们什么都不做,但它们仍然算作并行服务器。要么会话关闭,要么用户 运行 发出另一个查询,让我注意到并行使用的变化。但是,如果用户去喝咖啡、去发布或正在做其他事情,则不会有任何内容。 超过 100 个用户同时工作,您可能会感到头疼。我不得不设计一些解决方法:

我的问题如下:

对于这么长的问题,我深表歉意,但我不想留下任何东西。 如果对此有任何见解,我将不胜感激。

谢谢大家

您的查询并未真正完成。虽然您的查询仅提取前 1000 行,但 SQL 开发人员仅提取这 1000 行中的前 50 行。在您滚动到最后一行之前,IDE 不会关闭光标。一旦你检索了所有数据,那些并行进程就消失了。确保您看到“已提取所有行:在 X 秒内提取了 1000 行”,而不是“在 Y 秒内提取了 50 行”。(我希望 SQL 开发人员可以更直观地表明还有其他行在等待。)你不会在 SQL*Plus 中看到这个问题,因为 SQL*Plus 总是抓取所有行。

当仅获取前 N 行时,那些并行进程处于“活动”状态但未执行任何操作。您应该 能够忽略那些 session,因为它们没有使用任何重要资源。

如果您只是担心并行 session 的数量,您可能需要调整您的预期。我曾经和你处于同样的情况——不断地告诉用户他们的(不完整的)查询占用了所有并行的 sessions。最终,我发现这只是一个问题,因为我人为地创造了稀缺资源。 Oracle 并行进程通常是轻量级的,数据库可以支持比大多数人想象的更多的并行进程。

PARALLEL_MAX_SERVERS、PARALLEL_THREADS_PER_CPU 和 CPU_COUNT 的参数值是多少?查看 PARALLEL_MAX_SERVERS 的默认值。根据手册,默认数字为:PARALLEL_MAX_SERVERS = PARALLEL_THREADS_PER_CPU * CPU_COUNT * concurrent_parallel_users * 5.

大多数 DBA 看到并行线程的最大数量为数百个,恐慌,然后减少该数量。然后我们开始对开发人员大喊大叫,因为他们使用了人为限制的不重要资源。相反,我们应该将数字调回默认值,并忽略随机并行 sessions。如果用户没有超过 IO 或 CPU 限制,那么他们使用多少个并行线程应该无关紧要。

(除了防止 大量 并行查询 session 使用的可能例外。将您的用户置于不同的配置文件中,并将他们的 SESSIONS_PER_USER 设置为几十个。不要将其限制为 1 或 2 个。IDEs 需要额外的 sessions 用于多个选项卡、获取元数据的后台进程和调试 sessions。如果您设置限制为 2,您的开发人员将无法正确使用 IDE。)


编辑(回复评论)

我不确定您是否能深入了解 query coordinator 的状态。 QC 做几件事,但理想情况下,它大部分时间都是空闲的,而并行 sessions 处理大部分工作。

使用 producer/consumer 模型,一半的并行 session 可能正在接收数据但实际上没有做任何事情 - 就像它们只是某些操作中的内存结构。并行 sessions 可能会在活动和非活动之间切换,因为并非所有步骤都需要那么多 sessions。但是我们不希望 Oracle 在中间关闭 sessions,因为稍后可能需要它们,我们不想浪费时间打开和关闭 sessions.

有许多因素会影响并行度,但据我所知,增加 PARALLEL_MAX_SERVERS 不会影响单个语句请求的并行服务器数。 (但如果该语句要求的服务器数量已经超过最大值,则增加参数可能会影响分配的 session 数量)。

可能感觉 SQL 语句只是随机抓取所有并行的 session,但最终 DOP 计算几乎总是遵循确定性规则。只是规则太复杂了,很难说到底是怎么回事。例如,一个常见的混淆点是,每当查询添加排序或分组时,并行session的数量就会增加一倍。