强制 Oracle 对子查询使用散列连接

MK0*_*K01 5 oracle join optimization

我有一个查询,看起来像

SELECT *
FROM table0
WHERE id IN (SELECT id FROM table1 JOIN table2)
Run Code Online (Sandbox Code Playgroud)

Oracle 选择使用嵌套循环将 table0 与 (table1 x table2) 的结果连接起来,这需要几个小时。我试图弄清楚我是否可以暗示它使用 HASH 来代替,但不知道使用哪个提示以及在哪里使用。我尝试将 HASH_SJ 和 HASH_AJ 贴在各个地方,但没有帮助...

小智 6

我会尝试将WITH子句与MATERIALIZE提示结合使用,以首先强制实现子查询。像这样的东西:

WITH x as (select /*+ MATERIALIZE */
           from [your subquery join])
SELECT *
FROM table0, x
WHERE table0.id =x.id
Run Code Online (Sandbox Code Playgroud)


Vin*_*rat 5

您可以在子查询中使用提示,例如,在使用提示限定它们之后QB_NAME

然而,在这种情况下,一个简单的USE_HASH提示应该没问题。这是我的设置:

create table t0 (id integer primary key, pad char(500));
insert into t0 select rownum, 'x' from dual connect by level <= 2000;

create table t1 (t1_id integer primary key, id integer references t0, pad char(500));
insert into t1 select rownum, round(rownum/2), 'x' from dual connect by level <= 100;
create index i0 on t1(id);

create table t2 (t2_id integer primary key, t1_id integer references t1, pad char(500));
insert into t2 select rownum, round(rownum/2), 'x' from dual connect by level <= 100;
create index i1 on t2(t1_id);

exec dbms_stats.gather_table_stats(user, 'T0', cascade=>true);
exec dbms_stats.gather_table_stats(user, 'T1', cascade=>true);
exec dbms_stats.gather_table_stats(user, 'T2', cascade=>true);
Run Code Online (Sandbox Code Playgroud)

通过此设置,以下查询将运行 NESTED LOOP 连接:

SQL> EXPLAIN PLAN FOR
  2  SELECT * FROM t0
  3   WHERE id IN (SELECT id
  4                  FROM t1 JOIN t2 ON t1.t1_id = t2.t1_id
  5                 WHERE t2.pad LIKE :x);

Explained.

SQL> SELECT * FROM TABLE(DBMS_XPLAN.display);

-------------------------------------------------------------------------------
| Id  | Operation                    |  Name          | Rows  | Bytes | Cost  |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                |     5 |  2585 |    37 |
|   1 |  NESTED LOOPS                |                |     5 |  2585 |    37 |
|   2 |   VIEW                       | VW_NSO_1       |     5 |    65 |     7 |
|   3 |    SORT UNIQUE               |                |     5 |  2550 |       |
|   4 |     HASH JOIN                |                |     5 |  2550 |     7 |
|   5 |      TABLE ACCESS FULL       | T1             |   100 |   600 |     3 |
|   6 |      TABLE ACCESS FULL       | T2             |     5 |  2520 |     3 |
|   7 |   TABLE ACCESS BY INDEX ROWID| T0             |     1 |   504 |     1 |
|   8 |    INDEX UNIQUE SCAN         | SYS_C00746321  |     1 |       |       |
-------------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

随着USE_HASH提示:

SQL> EXPLAIN PLAN FOR
  2  SELECT /*+ USE_HASH (t0) */ * FROM t0
  3   WHERE id IN (SELECT id
  4                  FROM t1 JOIN t2 ON t1.t1_id = t2.t1_id
  5                 WHERE t2.pad LIKE :x);

Explained.

SQL> SELECT * FROM TABLE(DBMS_XPLAN.display);

--------------------------------------------------------------------
| Id  | Operation            |  Name       | Rows  | Bytes | Cost  |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT     |             |     5 |  2585 |    44 |
|   1 |  HASH JOIN SEMI      |             |     5 |  2585 |    44 |
|   2 |   TABLE ACCESS FULL  | T0          |  2000 |   984K|    23 |
|   3 |   VIEW               | VW_NSO_1    |     5 |    65 |     7 |
|   4 |    HASH JOIN         |             |     5 |  2550 |     7 |
|   5 |     TABLE ACCESS FULL| T1          |   100 |   600 |     3 |
|   6 |     TABLE ACCESS FULL| T2          |     5 |  2520 |     3 |
--------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

  • 在具有相同逻辑数据的两个实例之间(有时甚至在同一个实例中),有很多事情可以改变,从而产生不同的计划。不要因为两个不同的服务器产生不同的计划而假设您的安装被搞砸了。例如,统计数据可能略有不同,因此推动一个实例运行嵌套循环,而另一个运行散列连接。这是完全正常的。 (2认同)