【问题标题】:Is bind peeking disabled on distributed queries?分布式查询是否禁用绑定窥视?
【发布时间】:2012-08-31 12:34:00
【问题描述】:

在升级到 Oracle 11g 后,我在优化 Oracle 查询时遇到了问题,这个问题开始让我有点发疯。

请注意,这个问题现在已经完全编辑,因为我在创建一个简单的测试用例后获得了更多信息。原始问题可在此处获得:https://stackoverflow.com/revisions/12304320/1

这个问题是当连接两个表时,其中一个在日期列上具有between 条件,如果查询连接到远程表,则不会发生绑定窥视。

这是一个帮助重现问题的测试用例。首先设置两个源表。第一个是日期列表,是一个月的第一天,可以追溯到三十年前

create table mike_temp_etl_control
as 
select
  add_months(trunc(sysdate, 'MM'), 1-row_count) as reporting_date
from (
  select level as row_count
  from dual
  connect by level < 360
);

然后是来自dba_objects的一些数据:

create table mike_temp_dba_objects as
select owner, object_name, subobject_name, object_id, created
from dba_objects
union all
select owner, object_name, subobject_name, object_id, created
from dba_objects;

然后创建一个空表来运行数据:

create table mike_temp_1
as
select 
  a.OWNER,
  a.OBJECT_NAME,
  a.SUBOBJECT_NAME,
  a.OBJECT_ID,
  a.CREATED,
  b.REPORTING_DATE
from 
  mike_temp_dba_objects a
  join mike_temp_etl_control b on (
      b.reporting_date between add_months(a.created, -24) and a.created)
  where 1=2;

然后运行代码。您可能需要创建一个更大的版本 mike_temp_dba_objects 以减慢查询速度(或使用其他方法来获取执行计划)。在查询运行时,我通过从另一个会话运行 select * from table(dbms_xplan.display_cursor(sql_id => 'xxxxxxxxxxx')) 从会话中获取执行计划。

declare
  pv_report_start_date date := date '2002-01-01';
  v_report_end_date date := date '2012-07-01';

begin

  INSERT /*+ APPEND */
  INTO mike_temp_5
  select 
    a.OWNER,
    a.OBJECT_NAME,
    a.SUBOBJECT_NAME,
    a.OBJECT_ID,
    a.CREATED,
    b.REPORTING_DATE
from 
  mike_temp_dba_objects a
  join mike_temp_etl_control b on (
    b.reporting_date between add_months(a.created, -24) and a.created)
  cross join dual@emirrl -- This line causes problems...
where 
  b.reporting_date between add_months(pv_report_start_date, -12) and v_report_end_date;

  rollback;  
end;

通过在查询中有一个远程表,mike_temp_etl_control 表的基数估计是完全错误的,并且绑定偷看似乎没有发生。

上面查询的执行计划如下所示:

---------------------------------------------------------------------------------------
| Id  | Operation                | Name                  | Rows  | Bytes | Cost (%CPU)|
---------------------------------------------------------------------------------------
|   0 | INSERT STATEMENT         |                       |       |       |   373 (100)|
|   1 |  LOAD AS SELECT          |                       |       |       |            |
|*  2 |   FILTER                 |                       |       |       |            |
|   3 |    MERGE JOIN            |                       |     5 |   655 |   373  (21)|
|   4 |     SORT JOIN            |                       |  1096 |   130K|   370  (20)|
|   5 |      MERGE JOIN CARTESIAN|                       |  1096 |   130K|   369  (20)|
|   6 |       REMOTE             | DUAL                  |     1 |       |     2   (0)|
|   7 |       BUFFER SORT        |                       |  1096 |   130K|   367  (20)|
|*  8 |        TABLE ACCESS FULL | MIKE_TEMP_DBA_OBJECTS |  1096 |   130K|   367  (20)|
|*  9 |     FILTER               |                       |       |       |            |
|* 10 |      SORT JOIN           |                       |     2 |    18 |     3  (34)|
|* 11 |       TABLE ACCESS FULL  | MIKE_TEMP_ETL_CONTROL |     2 |    18 |     2   (0)|
---------------------------------------------------------------------------------------

如果我将远程 dual 替换为本地版本,我会得到正确的基数(139 而不是 2):

-------------------------------------------------------------------------------------
| Id  | Operation              | Name                  | Rows  | Bytes | Cost (%CPU)|
-------------------------------------------------------------------------------------
|   0 | INSERT STATEMENT       |                       |       |       | 10682 (100)|
|   1 |  LOAD AS SELECT        |                       |       |       |            |
|*  2 |   FILTER               |                       |       |       |            |
|   3 |    MERGE JOIN          |                       |   152K|    19M| 10682   (3)|
|   4 |     SORT JOIN          |                       |   438K|    51M| 10632   (2)|
|   5 |      NESTED LOOPS      |                       |   438K|    51M|   369  (20)|
|   6 |       FAST DUAL        |                       |     1 |       |     2   (0)|
|*  7 |       TABLE ACCESS FULL| MIKE_TEMP_DBA_OBJECTS |   438K|    51M|   367  (20)|
|*  8 |     FILTER             |                       |       |       |            |
|*  9 |      SORT JOIN         |                       |   139 |  1251 |     3  (34)|
|* 10 |       TABLE ACCESS FULL| MIKE_TEMP_ETL_CONTROL |   139 |  1251 |     2   (0)|
-------------------------------------------------------------------------------------

所以,我想问题是如何获得正确的基数来估计?这是 Oracle 错误还是预期的行为?

【问题讨论】:

  • 为了摆脱简单的东西,你有没有在桌子上重新聚集statistics
  • 是的,统计数据应该都是新鲜的。不过明天会再次检查。它是数据仓库 ETL 负载的一部分,在运行过程中会收集所有数据的统计信息
  • 我知道 > 11.1 版本中存在一个错误,该错误有一个循环工作,其中包括将“_optim_peek_user_binds”参数设置为 false。这会影响优化器,但我不知道具体如何。您可以检查此参数是否设置为 true 或 false,它应该为 true 以获得最佳性能。该错误导致 ORA-3137 错误。
  • @Gisli 我可能想反对 _optim_peek_user_binds = false,因为它似乎没有偷看。在我创建的其中一个跟踪文件中,该参数出现并设置为 true。另外,我没有收到错误消息。
  • 我已经和我的 DBA 谈过了(虽然我正在等待收到任何回复)并且开始认为这可能是一个错误……尤其是在没有答案的情况下。跨度>

标签: sql oracle plsql oracle11g


【解决方案1】:

我认为你应该搞砸动态采样。它在 11g 中的工作方式不同,所以这可能是您遇到问题的原因。

【讨论】:

    猜你喜欢
    • 2018-12-12
    • 2017-11-12
    • 2020-11-09
    • 2011-01-04
    • 2013-02-25
    • 1970-01-01
    • 2014-01-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多