作为 SQL 开发人员或 Toad 使用 IDE 工具的 Oracle 并行查询行为
Oracle Parallel Query behaviour with IDE tools as SQL Developer or Toad
一段时间以来,我一直在努力抽出时间来写这个问题,并尽我所能解释这个问题,所以请提前原谅我的长文。
我的环境:
- Oracle 数据库 12.2 运行在 Red Hat 7 上运行(R.A.C 2 个节点)- 每个节点 16CPU 和 64GB RAM。
- Parallel Force Local 设置为 TRUE 以强制并行服务器进程只能在启动 SQL 语句的同一节点上执行。
我们有一个非常大的数据库,其中包含许多服务于多个应用程序的模式。大多数应用程序实际上是 PL/SQL 中处理数亿条记录的批处理引擎,因此出于性能原因,大多数大型 tables 都配置了 PARALLEL DEGREE DEFAULT。表已分区并具有高级压缩功能。
除了一些用于开发目的的报告 BI 工具外,许多最终用户还可以通过 SQL 开发人员访问系统(仅在读取模式下)以进行 QA 检查。我从来不喜欢,但有时候你不得不接受事情的本来面目。
为了控制一些事情,我设计了一个特定的登录触发器,它不仅包括审计功能,还包括传入会话的某些方面:
- 使用 SQL 开发人员访问的最终用户可能只打开 2 个会话。
- 最终用户通过 SQL 开发人员访问 运行 立即执行 ALTER SESSION DISABLE PARALLEL QUERY。不幸的是,我知道有些用户正在自行激活它。 ALTER SESSION ENABLE/DISABLE PARALLEL QUERY 被 CREATE SESSION 特权或 CONNECT 角色继承,所以我对此无能为力。
- 使用 SQL 开发人员访问的最终用户被分配到一个特定的配置文件,在 CPU 、磁盘读取等方面受到限制
登录触发器允许或不允许基于一组附加规则的访问,但对于问题的目的,它们并不重要。
让我们看看 运行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 个用户同时工作,您可能会感到头疼。我不得不设计一些解决方法:
- 我必须在触发器内创建一个新控件来识别处于活动状态的 QC 与从属的非活动时间,以便识别用户已经打开了多少会话。
- 在 window 1 小时
后,我必须创建一个清理进程以断开处于此状态的会话
- 我不能在配置文件中使用限制会话,因为它们在 QC 或 SLAVES 之间没有区别。
- 无论我配置了多少东西,有时我 运行 没有并行进程,如果在工作时间执行批处理(这种情况经常发生),我有时会遇到那些重要的并行可用性不足的问题由于非活动会话占用的从属数量而导致的进程。
我的问题如下:
- 为什么在QC已经结束的时候slaves还停留在ACTIVE状态?不应该在 QC 交付结果后立即终止 slaves 吗?
- 为什么在 SQLPLUS 和 Java 池解决方案(作为 SAP Business Objects)中当它们 运行 非常相似的查询时都不会发生这种行为?
- 有没有办法禁用最终用户的并行功能,无论他们尝试通过启用并行查询还是通过提示来激活它们?
对于这么长的问题,我深表歉意,但我不想留下任何东西。
如果对此有任何见解,我将不胜感激。
谢谢大家
您的查询并未真正完成。虽然您的查询仅提取前 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的数量就会增加一倍。
一段时间以来,我一直在努力抽出时间来写这个问题,并尽我所能解释这个问题,所以请提前原谅我的长文。
我的环境:
- Oracle 数据库 12.2 运行在 Red Hat 7 上运行(R.A.C 2 个节点)- 每个节点 16CPU 和 64GB RAM。
- Parallel Force Local 设置为 TRUE 以强制并行服务器进程只能在启动 SQL 语句的同一节点上执行。
我们有一个非常大的数据库,其中包含许多服务于多个应用程序的模式。大多数应用程序实际上是 PL/SQL 中处理数亿条记录的批处理引擎,因此出于性能原因,大多数大型 tables 都配置了 PARALLEL DEGREE DEFAULT。表已分区并具有高级压缩功能。
除了一些用于开发目的的报告 BI 工具外,许多最终用户还可以通过 SQL 开发人员访问系统(仅在读取模式下)以进行 QA 检查。我从来不喜欢,但有时候你不得不接受事情的本来面目。
为了控制一些事情,我设计了一个特定的登录触发器,它不仅包括审计功能,还包括传入会话的某些方面:
- 使用 SQL 开发人员访问的最终用户可能只打开 2 个会话。
- 最终用户通过 SQL 开发人员访问 运行 立即执行 ALTER SESSION DISABLE PARALLEL QUERY。不幸的是,我知道有些用户正在自行激活它。 ALTER SESSION ENABLE/DISABLE PARALLEL QUERY 被 CREATE SESSION 特权或 CONNECT 角色继承,所以我对此无能为力。
- 使用 SQL 开发人员访问的最终用户被分配到一个特定的配置文件,在 CPU 、磁盘读取等方面受到限制
登录触发器允许或不允许基于一组附加规则的访问,但对于问题的目的,它们并不重要。
让我们看看 运行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 个用户同时工作,您可能会感到头疼。我不得不设计一些解决方法:
- 我必须在触发器内创建一个新控件来识别处于活动状态的 QC 与从属的非活动时间,以便识别用户已经打开了多少会话。
- 在 window 1 小时 后,我必须创建一个清理进程以断开处于此状态的会话
- 我不能在配置文件中使用限制会话,因为它们在 QC 或 SLAVES 之间没有区别。
- 无论我配置了多少东西,有时我 运行 没有并行进程,如果在工作时间执行批处理(这种情况经常发生),我有时会遇到那些重要的并行可用性不足的问题由于非活动会话占用的从属数量而导致的进程。
我的问题如下:
- 为什么在QC已经结束的时候slaves还停留在ACTIVE状态?不应该在 QC 交付结果后立即终止 slaves 吗?
- 为什么在 SQLPLUS 和 Java 池解决方案(作为 SAP Business Objects)中当它们 运行 非常相似的查询时都不会发生这种行为?
- 有没有办法禁用最终用户的并行功能,无论他们尝试通过启用并行查询还是通过提示来激活它们?
对于这么长的问题,我深表歉意,但我不想留下任何东西。 如果对此有任何见解,我将不胜感激。
谢谢大家
您的查询并未真正完成。虽然您的查询仅提取前 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的数量就会增加一倍。